55 Commits
Author SHA1 Message Date
Thomas StoddardandKyle Schwarz 8cd907250d Bindings: Python: Add Main51MessageFilter support 2026-09-21 13:39:27 -04:00
David RebbeandKyle Schwarz bb892bfd9b Bindings: Python: Support multi-config generators for stubgen 2026-09-17 11:27:23 -04:00
William SkellengerandKyle Schwarz 8801e949da CI: Enable interruptible 2026-09-15 17:37:51 -04:00
Samuel BejkoandKyle Schwarz d95a17b360 LIN: Add wakeup request 2026-09-14 17:13:23 -04:00
Kurt WachowskiandKyle Schwarz 3a6501d116 Device: Add ISO-15765 hardware acceleration 2026-09-10 20:52:01 -04:00
Bryant JonesandKyle Schwarz 34875129ee Gigastar: Add FLEXRAY_01 network 2026-09-10 14:18:24 -04:00
Jonathan SchwartzandKyle Schwarz 236c6ad089 Device: Add manufacturing config message 2026-09-10 12:56:55 -04:00
Max Brombach cf58f819cb Platform: Darwin: Replace deprecate kIOMasterPortDefault with kIOMainPortDefault 2026-08-27 18:33:01 +00:00
Kyle Schwarz 07e4eca14a Heartbeat: Include DeviceStatus 2026-08-17 15:34:16 -04:00
Max BrombachandKyle Schwarz 936566170f Communication: Add GenericAPIDataMessage and GenericAPIStatusMessage types 2026-08-17 10:30:35 -04:00
Kyle Schwarz 3aaacb6cc8 Device: Refactor heartbeat 2026-08-06 13:21:35 -04:00
Max BrombachandKyle Schwarz 1dda9f5412 Device: Add sendSPIPortKeyOperation() 2026-08-04 15:42:21 -04:00
Max Brombach 78c2e3ff89 Device: RAD-wBMS: Fix missing include for disk driver 2026-08-04 18:06:01 +00:00
Kyle Schwarz afedd4bb1f Servd: Add pushRx error 2026-07-29 17:44:58 -04:00
Kyle Schwarz 9b01e488da Build: Resolve warnings 2026-07-24 13:09:29 -04:00
David RebbeandKyle Schwarz 77a886bbe0 C2: Validate MAC network IDs 2026-07-21 13:30:21 -04:00
David RebbeandKyle Schwarz aff547b738 C2: Report copied buffer lengths 2026-07-21 13:07:06 -04:00
Max BrombachandKyle Schwarz 7a5c8c2879 Device: RAD-wBMS: Add class, chips, and bootloader information 2026-07-20 13:01:56 -04:00
Thomas StoddardandKyle Schwarz 0dd8dbfb64 Communication: Command: Add Main51 errors 2026-07-07 21:47:52 -04:00
David RebbeandKyle Schwarz d708f8081a C2: Add termination group support 2026-07-07 21:25:23 -04:00
David RebbeandKyle Schwarz 743246e813 Legacy: Update icsnVC40.h to Vehicle Spy 3.26.3.9 2026-07-07 20:51:37 -04:00
Max BrombachandKyle Schwarz 4ed29b4a5e Device: Add Failed enum value to Device::OpenStatusType enum 2026-06-29 16:13:39 -04:00
Jonathan SchwartzandKyle Schwarz 55d69246b0 Device: FIRE3: Add EnterBootloader phase 2026-06-29 12:19:02 -04:00
David RebbeandKyle Schwarz 19232def41 C2: Add icsneoc2_device_force_disk_config_update 2026-06-29 09:55:18 -04:00
David RebbeandKyle Schwarz 9d91524dc0 C2: Add EthernetStatusMessage 2026-06-29 09:08:51 -04:00
David RebbeandKyle Schwarz d86e3164af C2: Add AppError support 2026-06-26 17:32:43 -04:00
David RebbeandKyle Schwarz 3d99898598 FIRE3: Fix termination groups 2026-06-25 16:59:09 -04:00
David RebbeandKyle Schwarz 4b9cf1a37f Device: RAD: Add reboot support 2026-06-25 14:06:43 -04:00
David RebbeandKyle Schwarz 40d83f3b7c C2: Add device_product_name_get() 2026-06-24 16:58:28 -04:00
David RebbeandKyle Schwarz 60918c4b6d C2: Add PerfTest setting 2026-06-24 15:16:51 -04:00
Bryant JonesandKyle Schwarz 749552e443 Device: Fix coremini loading
For:
- RADA2B
- RADComet2
- RADComet3
- RADGalaxy2
- RADMoonT1S
- RADStar2
2026-06-24 13:28:12 -04:00
David RebbeandKyle Schwarz 8af6d5f2a8 FIRE3: Add reboot support 2026-06-19 17:58:49 -04:00
David RebbeandKyle Schwarz 54fb89b675 Settings: Add Linux options 2026-06-19 17:12:42 -04:00
Thomas StoddardandKyle Schwarz 299766403f Settings: Add GPTP 2026-06-18 22:23:13 -04:00
Max Brombach 2d0b0c63ed Device: RAD-Star 2: Add bootloader pipeline and chip info 2026-06-18 15:30:21 +00:00
Bryant JonesandKyle Schwarz 30606be7a8 Settings: Add PerfTest 2026-06-18 11:12:13 -04:00
Kyle Schwarz 4dd97f734a Servd: Disable signal on send failure 2026-06-18 10:21:35 -04:00
Bryant JonesandKyle Schwarz 44d0e3de64 Gigastar2: Fix loading coremini 2026-06-10 18:08:02 -04:00
Kyle Schwarz 023f5aa089 Bindings: Python: Add AppError 2026-06-10 16:59:43 -04:00
Kyle Schwarz bb711ae7e2 Event: Store device as weak pointer 2026-06-02 17:19:23 -04:00
Kyle Schwarz 476b5ff35c FIRE3: Add MDIO_01 network 2026-06-02 13:19:56 -04:00
Jonathan SchwartzandKyle Schwarz 99792a0ee1 Communication: Increase max packet length 2026-06-02 11:10:16 -04:00
Max BrombachandKyle Schwarz d42c51d772 EventManager: Fix Event Manager being accessed after static destruction 2026-05-22 15:56:02 -04:00
Thomas StoddardandKyle Schwarz 3ab06199c3 Device: Add ExtendedCommand::GetAllMACAddresses 2026-05-22 11:40:44 -04:00
Max BrombachandKyle Schwarz 49e578a657 Device: RAD-Comet and RAD-Comet 2: Replace all references to RAD-Comet with RAD-Comet2 2026-05-19 13:17:12 -04:00
Kyle Schwarz 0bf279c7b9 Build: Add WORKING_DIRECTORY to git commands 2026-05-15 14:55:17 -04:00
Kyle Schwarz 9de0cf688c Build: Parse CMake version from git 2026-05-14 23:16:20 -04:00
David RebbeandKyle Schwarz eded388b83 C2: Add message timestamp support 2026-05-14 22:16:41 -04:00
Kyle Schwarz 00b7b4a6de CI: Set ICSPB_BOOTSTRAP_DIR 2026-05-14 21:29:24 -04:00
Thomas StoddardandKyle Schwarz 0ecb360195 RADComet1: Deprecate and replace with RADComet2 2026-05-14 20:20:46 -04:00
David RebbeandKyle Schwarz b3bb033ecb C2: Add Supported Device Types" 2026-05-14 19:08:11 -04:00
David RebbeandKyle Schwarz c3762bbf22 C2: Add ChipVersions
Also fixes some formatting issues.
2026-05-14 13:39:39 -04:00
Thomas StoddardandKyle Schwarz e926e10dc5 RADGigastar2: Add to MACsecConfig 2026-05-14 11:29:54 -04:00
Thomas StoddardandKyle Schwarz 5620c98eda Examples: Add more error reporting 2026-05-13 17:03:01 -04:00
Thomas StoddardandKyle Schwarz c466d75dae All: neoVI Explorer -> ICS Device Manager 2026-05-13 15:45:28 -04:00
203 changed files with 10480 additions and 2477 deletions
+12 -27
View File
@@ -1,3 +1,6 @@
default:
interruptible: true
variables: variables:
DEBIAN_FRONTEND: noninteractive DEBIAN_FRONTEND: noninteractive
LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT} LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT}
@@ -35,30 +38,6 @@ unit_test windows/x64:
- libicsneo-win-x64 - libicsneo-win-x64
timeout: 5m timeout: 5m
build windows/x86:
stage: build
script:
- cmd /C ci\build-windows32.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- libicsneo-win-x64
unit_test windows/x86:
stage: unit_test
script:
- build\libicsneo-unit-tests.exe
dependencies:
- build windows/x86
needs:
- build windows/x86
tags:
- libicsneo-win-x64
timeout: 5m
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Ubuntu # Ubuntu
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@@ -303,7 +282,8 @@ build python/linux/amd64:
CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh
CIBW_BUILD: "*manylinux*" # no musl CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: x86_64 CIBW_ARCHS: x86_64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install CIBW_ENVIRONMENT: PCAP_ROOT=/project/libpcap/install
SKBUILD_CMAKE_DEFINE: ICSPB_BOOTSTRAP_DIR=/project/icspb
script: script:
- sh ci/build-wheel-posix.sh - sh ci/build-wheel-posix.sh
artifacts: artifacts:
@@ -318,7 +298,8 @@ build python/linux/arm64:
CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh
CIBW_BUILD: "*manylinux*" # no musl CIBW_BUILD: "*manylinux*" # no musl
CIBW_ARCHS: aarch64 CIBW_ARCHS: aarch64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install CIBW_ENVIRONMENT: PCAP_ROOT=/project/libpcap/install
SKBUILD_CMAKE_DEFINE: ICSPB_BOOTSTRAP_DIR=/project/icspb
script: script:
- sh ci/build-wheel-posix.sh - sh ci/build-wheel-posix.sh
artifacts: artifacts:
@@ -332,7 +313,8 @@ build python/macos:
variables: variables:
CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh CIBW_BEFORE_ALL: sh ci/bootstrap-libpcap.sh
CIBW_ARCHS: arm64 CIBW_ARCHS: arm64
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=$CI_PROJECT_DIR/libpcap/install CIBW_ENVIRONMENT: PCAP_ROOT=$CI_PROJECT_DIR/libpcap/install
SKBUILD_CMAKE_DEFINE: ICSPB_BOOTSTRAP_DIR=$CI_PROJECT_DIR/icspb
MACOSX_DEPLOYMENT_TARGET: 10.14 MACOSX_DEPLOYMENT_TARGET: 10.14
script: script:
- sh ci/build-wheel-posix.sh - sh ci/build-wheel-posix.sh
@@ -347,6 +329,7 @@ build python/windows:
variables: variables:
CIBW_ARCHS: AMD64 CIBW_ARCHS: AMD64
CIBW_ENVIRONMENT: CMAKE_GENERATOR=Ninja CIBW_ENVIRONMENT: CMAKE_GENERATOR=Ninja
SKBUILD_CMAKE_DEFINE: ICSPB_BOOTSTRAP_DIR=$CI_PROJECT_DIR/icspb
script: script:
- cmd /c ci\build-wheel-windows.bat - cmd /c ci\build-wheel-windows.bat
artifacts: artifacts:
@@ -355,6 +338,7 @@ build python/windows:
deploy python/pypi: deploy python/pypi:
stage: deploy stage: deploy
interruptible: false
variables: variables:
TWINE_USERNAME: __token__ TWINE_USERNAME: __token__
TWINE_PASSWORD: $PYPI_TOKEN TWINE_PASSWORD: $PYPI_TOKEN
@@ -379,6 +363,7 @@ deploy python/pypi:
push github: push github:
stage: deploy stage: deploy
interruptible: false
tags: tags:
- linux-build - linux-build
image: alpine:latest image: alpine:latest
+49 -2
View File
@@ -1,5 +1,43 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(libicsneo VERSION 1.0.0)
function(git_tag_version VERSION_RESULT)
set(${VERSION_RESULT} "0.0.0.0" PARENT_SCOPE)
find_package(Git)
if(NOT Git_FOUND)
return()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE LAST_TAG
RESULT_VARIABLE RESULT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT RESULT EQUAL 0)
return()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-list ${LAST_TAG}..HEAD --count
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE COMMIT_COUNT_SINCE_TAG
RESULT_VARIABLE RESULT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT RESULT EQUAL 0)
return()
endif()
set(${VERSION_RESULT} "${LAST_TAG}.${COMMIT_COUNT_SINCE_TAG}" PARENT_SCOPE)
endfunction()
git_tag_version(LIBICSNEO_VERSION)
if(LIBICSNEO_VERSION STREQUAL "0.0.0.0")
message(WARNING "Unable to parse version from git history")
endif()
project(libicsneo VERSION ${LIBICSNEO_VERSION})
cmake_policy(SET CMP0074 NEW) cmake_policy(SET CMP0074 NEW)
if(POLICY CMP0135) if(POLICY CMP0135)
@@ -44,7 +82,7 @@ if(MSVC)
add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0) add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(LIBICSNEO_COMPILER_WARNINGS -Wall -Wno-switch -Wno-unknown-pragmas) set(LIBICSNEO_COMPILER_WARNINGS -Wall -Wno-unknown-pragmas)
endif() endif()
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
@@ -192,10 +230,18 @@ set(SRC_FILES
communication/message/logdatamessage.cpp communication/message/logdatamessage.cpp
communication/message/tc10statusmessage.cpp communication/message/tc10statusmessage.cpp
communication/message/gptpstatusmessage.cpp communication/message/gptpstatusmessage.cpp
communication/message/allmacaddressesmessage.cpp
communication/message/ethernetstatusmessage.cpp communication/message/ethernetstatusmessage.cpp
communication/message/networkmutexmessage.cpp communication/message/networkmutexmessage.cpp
communication/message/clientidmessage.cpp communication/message/clientidmessage.cpp
communication/message/mfgconfigmessage.cpp
communication/message/transmitmessage.cpp communication/message/transmitmessage.cpp
communication/message/spiportkeymessage.cpp
communication/message/genericapidatamessage.cpp
communication/message/genericapistatusmessage.cpp
communication/message/iso15765message.cpp
communication/packet/flexraypacket.cpp communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp communication/packet/a2bpacket.cpp
@@ -306,6 +352,7 @@ add_library(icsneocpp
api/icsneocpp/icsneocpp.cpp api/icsneocpp/icsneocpp.cpp
api/icsneocpp/event.cpp api/icsneocpp/event.cpp
api/icsneocpp/eventmanager.cpp api/icsneocpp/eventmanager.cpp
api/icsneocpp/heartbeat.cpp
api/icsneocpp/version.cpp api/icsneocpp/version.cpp
${SRC_FILES} ${SRC_FILES}
) )
+1 -1
View File
@@ -45,7 +45,7 @@ Instructions for installing each API can be found in its respective documentatio
- RAD-Pluto - RAD-Pluto
- RAD-Star 2 - RAD-Star 2
- RAD-SuperMoon - RAD-SuperMoon
- RADComet - RAD-wBMS
- ValueCAN 3 - ValueCAN 3
- ValueCAN 4 - ValueCAN 4
+309 -22
View File
@@ -5,6 +5,7 @@
#include "icsneo/device/devicefinder.h" #include "icsneo/device/devicefinder.h"
#include "icsneo/icsneocpp.h" #include "icsneo/icsneocpp.h"
#include "icsneo/communication/io.h" #include "icsneo/communication/io.h"
#include "icsneo/communication/network.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -12,8 +13,10 @@
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <optional> #include <optional>
#include <chrono>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <cstring>
using namespace icsneo; using namespace icsneo;
@@ -69,6 +72,7 @@ icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, char* valu
"Close failed", // icsneoc2_error_close_failed "Close failed", // icsneoc2_error_close_failed
"Reconnect failed", // icsneoc2_error_reconnect_failed "Reconnect failed", // icsneoc2_error_reconnect_failed
"Invalid data", // icsneoc2_error_invalid_data "Invalid data", // icsneoc2_error_invalid_data
"Force disk config update failed", // icsneoc2_error_force_disk_config_update_failed
}; };
static_assert(std::size(error_strings) == icsneoc2_error_maxsize, static_assert(std::size(error_strings) == icsneoc2_error_maxsize,
"error_strings is out of sync with _icsneoc2_error_t enum - update both together"); "error_strings is out of sync with _icsneoc2_error_t enum - update both together");
@@ -84,6 +88,61 @@ icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, char* valu
return safe_str_copy(value, value_length, error_strings[error_code]) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; return safe_str_copy(value, value_length, error_strings[error_code]) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
} }
icsneoc2_error_t icsneoc2_supported_devices_enumerate(icsneoc2_supported_device_t** supported_devices) {
if(!supported_devices) {
return icsneoc2_error_invalid_parameters;
}
auto device_types = DeviceFinder::GetSupportedDevices();
icsneoc2_supported_device_t* head = nullptr;
icsneoc2_supported_device_t* tail = nullptr;
for(auto& device_type : device_types) {
auto* node = new (std::nothrow) icsneoc2_supported_device_t;
if(!node) {
return icsneoc2_error_out_of_memory;
}
node->device_type = device_type;
node->next = nullptr;
if(!head) {
head = node;
} else {
tail->next = node;
}
tail = node;
}
*supported_devices = head;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_supported_devices_free(icsneoc2_supported_device_t* supported_devices) {
if(!supported_devices) {
return icsneoc2_error_invalid_parameters;
}
while(supported_devices) {
auto* next = supported_devices->next;
delete supported_devices;
supported_devices = next;
}
return icsneoc2_error_success;
}
icsneoc2_supported_device_t* icsneoc2_supported_devices_next(const icsneoc2_supported_device_t* supported_device) {
if(!supported_device) {
return nullptr;
}
return supported_device->next;
}
icsneoc2_error_t icsneoc2_supported_device_get(const icsneoc2_supported_device_t* supported_device, icsneoc2_devicetype_t* device_type) {
if(!supported_device || !device_type) {
return icsneoc2_error_invalid_parameters;
}
*device_type = static_cast<icsneoc2_devicetype_t>(supported_device->device_type);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_type_name_get(icsneoc2_devicetype_t device_type, char* value, size_t* value_length) { icsneoc2_error_t icsneoc2_device_type_name_get(icsneoc2_devicetype_t device_type, char* value, size_t* value_length) {
if(!value || !value_length) { if(!value || !value_length) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
@@ -214,7 +273,9 @@ static icsneoc2_error_t open_device_with_options(std::shared_ptr<Device> dev, ic
if(!dev) { if(!dev) {
return icsneoc2_error_invalid_device; return icsneoc2_error_invalid_device;
} }
if(!dev->enableMessagePolling(std::make_optional<MessageFilter>())) { MessageFilter filter;
filter.includeInternalInAny = true;
if(!dev->enableMessagePolling(std::make_optional(filter))) {
return icsneoc2_error_enable_message_polling_failed; return icsneoc2_error_enable_message_polling_failed;
} }
if(!dev->isOpen() && !dev->open()) { if(!dev->isOpen() && !dev->open()) {
@@ -251,12 +312,12 @@ icsneoc2_error_t icsneoc2_device_open_serial(const char* serial, icsneoc2_open_o
std::string_view target(serial); std::string_view target(serial);
for(auto* cur = devs; cur; cur = cur->next) { for(auto* cur = devs; cur; cur = cur->next) {
if(cur->device && cur->device->getSerial() == target) { if(cur->device && cur->device->getSerial() == target) {
if (res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) { if(res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) {
icsneoc2_enumeration_free(devs); icsneoc2_enumeration_free(devs);
return res; return res;
} }
res = open_device_with_options((*device)->device, options); res = open_device_with_options((*device)->device, options);
if (res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_device_free(*device); icsneoc2_device_free(*device);
*device = nullptr; *device = nullptr;
} }
@@ -279,12 +340,12 @@ icsneoc2_error_t icsneoc2_device_open_first(icsneoc2_devicetype_t device_type, i
} }
for(auto* cur = devs; cur; cur = cur->next) { for(auto* cur = devs; cur; cur = cur->next) {
if(cur->device && !cur->device->isOpen()) { if(cur->device && !cur->device->isOpen()) {
if (res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) { if(res = icsneoc2_device_create(cur, device); res != icsneoc2_error_success) {
icsneoc2_enumeration_free(devs); icsneoc2_enumeration_free(devs);
return res; return res;
} }
res = open_device_with_options((*device)->device, options); res = open_device_with_options((*device)->device, options);
if (res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
icsneoc2_device_free(*device); icsneoc2_device_free(*device);
*device = nullptr; *device = nullptr;
} }
@@ -302,7 +363,7 @@ icsneoc2_error_t icsneoc2_device_reconnect(icsneoc2_device_t* device, icsneoc2_o
return res; return res;
} }
// If the device is currently open, close it first before trying to reconnect // If the device is currently open, close it first before trying to reconnect
if (device->device->isOpen()) { if(device->device->isOpen()) {
res = icsneoc2_device_close(device); res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return res; return res;
@@ -342,7 +403,7 @@ icsneoc2_error_t icsneoc2_device_free(icsneoc2_device_t* device) {
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return res; return res;
} }
if (device->device->isOpen()) { if(device->device->isOpen()) {
res = icsneoc2_device_close(device); res = icsneoc2_device_close(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return res; return res;
@@ -382,6 +443,16 @@ icsneoc2_error_t icsneoc2_device_serial_get(const icsneoc2_device_t* device, cha
return safe_str_copy(value, value_length, dev->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed; return safe_str_copy(value, value_length, dev->getSerial()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
} }
icsneoc2_error_t icsneoc2_device_product_name_get(const icsneoc2_device_t* device, char* value, size_t* value_length) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
auto dev = device->device;
// Copy the string into value
return safe_str_copy(value, value_length, dev->getProductName()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
}
icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) { icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
@@ -395,35 +466,94 @@ icsneoc2_error_t icsneoc2_device_pcb_serial_get(const icsneoc2_device_t* device,
return icsneoc2_error_invalid_type; return icsneoc2_error_invalid_type;
} }
const auto& data = *pcbSerial; const auto& data = *pcbSerial;
if(value) { if(!value) {
size_t copyLen = std::min(*value_length, data.size()); *value_length = data.size();
std::copy(data.begin(), data.begin() + copyLen, value); return icsneoc2_error_success;
} }
*value_length = data.size(); size_t copyLen = std::min(*value_length, data.size());
std::copy(data.begin(), data.begin() + copyLen, value);
*value_length = copyLen;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_mac_address_get(const icsneoc2_device_t* device, uint8_t* value, size_t* value_length) { icsneoc2_error_t icsneoc2_device_mac_addresses_enumerate(const icsneoc2_device_t* device, icsneoc2_mac_addr_entry_t** mac_entries) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return res; return res;
} }
if(!value_length) { if(!mac_entries) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
} }
auto macAddress = device->device->getMACAddress(); const auto result = device->device->getMACAddresses();
if(!macAddress.has_value()) { if(result.empty()) {
return icsneoc2_error_invalid_type; return icsneoc2_error_invalid_type;
} }
const auto& data = *macAddress; icsneoc2_mac_addr_entry_t* head = nullptr;
if(value) { icsneoc2_mac_addr_entry_t* tail = nullptr;
size_t copyLen = std::min(*value_length, data.size()); for(auto addr_pair : result) {
std::copy(data.begin(), data.begin() + copyLen, value); auto* node = new (std::nothrow) icsneoc2_mac_addr_entry_t;
if(!node) {
icsneoc2_mac_addresses_free(head);
return icsneoc2_error_out_of_memory;
}
node->network_id = static_cast<uint16_t>(addr_pair.first);
std::copy(addr_pair.second.begin(), addr_pair.second.end(), node->address);
node->next = nullptr;
if(!head) {
head = node;
} else {
tail->next = node;
}
tail = node;
} }
*value_length = data.size(); *mac_entries = head;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_mac_network_id_get(const icsneoc2_mac_addr_entry_t* mac_address, icsneoc2_netid_t* network_id) {
if(!mac_address || !network_id) {
return icsneoc2_error_invalid_parameters;
}
const auto netid = static_cast<Network::NetID>(mac_address->network_id);
*network_id = Network::GetCoreMiniNetworkFromNetID(netid).has_value()
? mac_address->network_id
: static_cast<icsneoc2_netid_t>(icsneoc2_netid_invalid);
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_mac_address_get(const icsneoc2_mac_addr_entry_t* mac_address, uint8_t* value, size_t* value_length) {
if(!mac_address || !value_length) {
return icsneoc2_error_invalid_parameters;
}
if(!value) {
*value_length = static_cast<size_t>(ICSNEO_MAC_ADDRESS_LEN);
return icsneoc2_error_success;
}
size_t copyLen = std::min(*value_length, static_cast<size_t>(ICSNEO_MAC_ADDRESS_LEN));
std::copy(mac_address->address, mac_address->address + copyLen, value);
*value_length = copyLen;
return icsneoc2_error_success;
}
icsneoc2_mac_addr_entry_t* icsneoc2_mac_addresses_next(const icsneoc2_mac_addr_entry_t* mac_address) {
if(!mac_address) {
return nullptr;
}
return mac_address->next;
}
icsneoc2_error_t icsneoc2_mac_addresses_free(icsneoc2_mac_addr_entry_t* mac_address) {
if(!mac_address) {
return icsneoc2_error_invalid_parameters;
}
while(mac_address) {
auto* next = mac_address->next;
delete mac_address;
mac_address = next;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_go_online(const icsneoc2_device_t* device, bool go_online) { icsneoc2_error_t icsneoc2_device_go_online(const icsneoc2_device_t* device, bool go_online) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
@@ -671,15 +801,76 @@ icsneoc2_error_t icsneoc2_device_tc10_status_get(const icsneoc2_device_t* device
if(!cpp_status.has_value()) { if(!cpp_status.has_value()) {
return icsneoc2_error_invalid_type; return icsneoc2_error_invalid_type;
} }
if (sleep_status) { if(sleep_status) {
*sleep_status = static_cast<icsneoc2_tc10_sleep_status_t>(cpp_status->sleepStatus); *sleep_status = static_cast<icsneoc2_tc10_sleep_status_t>(cpp_status->sleepStatus);
} }
if (wake_status) { if(wake_status) {
*wake_status = static_cast<icsneoc2_tc10_wake_status_t>(cpp_status->wakeStatus); *wake_status = static_cast<icsneoc2_tc10_wake_status_t>(cpp_status->wakeStatus);
} }
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_supports_gptp(const icsneoc2_device_t* device, bool* supported) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!supported) {
return icsneoc2_error_invalid_parameters;
}
*supported = device->device->supportsGPTP();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_gptp_status_get(const icsneoc2_device_t* device, uint32_t timeout_ms, icsneoc2_gptp_status_t* status) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!status) {
return icsneoc2_error_invalid_parameters;
}
auto cpp_status = device->device->getGPTPStatus(std::chrono::milliseconds(timeout_ms));
if(!cpp_status.has_value()) {
return icsneoc2_error_get_settings_failure;
}
status->current_time_seconds = cpp_status->currentTime.seconds;
status->current_time_nanoseconds = cpp_status->currentTime.nanoseconds;
status->ms_offset_ns = cpp_status->msOffsetNs;
status->is_sync = cpp_status->isSync;
status->link_status = cpp_status->linkStatus;
status->link_delay_ns = cpp_status->linkDelayNS;
status->selected_role = cpp_status->selectedRole;
status->as_capable = cpp_status->asCapable;
status->is_syntonized = cpp_status->isSyntonized;
status->short_format = cpp_status->shortFormat;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_supports_reboot(const icsneoc2_device_t* device, bool* supported) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!supported) {
return icsneoc2_error_invalid_parameters;
}
*supported = device->device->supportsReboot();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_reboot(const icsneoc2_device_t* device, bool safe) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->reboot(safe)) {
return icsneoc2_error_transmit_message_failed;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) { icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
@@ -916,6 +1107,21 @@ icsneoc2_error_t icsneoc2_device_format_disk(const icsneoc2_device_t* device, ic
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_force_disk_config_update(const icsneoc2_device_t* device, icsneoc2_disk_details_t* disk_details) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!disk_details || !disk_details->details) {
return icsneoc2_error_invalid_parameters;
}
if(!device->device->forceDiskConfigUpdate(*disk_details->details)) {
return icsneoc2_error_force_disk_config_update_failed;
}
return icsneoc2_error_success;
}
static icsneoc2_error_t get_supported_networks(const icsneoc2_device_t* device, const std::vector<Network>& nets, icsneoc2_netid_t* networks, size_t* count) { static icsneoc2_error_t get_supported_networks(const icsneoc2_device_t* device, const std::vector<Network>& nets, icsneoc2_netid_t* networks, size_t* count) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
@@ -1208,3 +1414,84 @@ icsneoc2_error_t icsneoc2_script_status_max_coremini_size_kb_get(const icsneoc2_
*value = script_status->status->maxCoreminiSizeKB; *value = script_status->status->maxCoreminiSizeKB;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_chip_versions_enumerate(const icsneoc2_device_t* device, icsneoc2_chip_versions_t** chip_versions, bool refresh, size_t* count) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!chip_versions) {
return icsneoc2_error_invalid_parameters;
}
auto version_reports = device->device->getChipVersions(refresh);
if(count) {
*count = version_reports.size();
}
icsneoc2_chip_versions_t* head = nullptr;
icsneoc2_chip_versions_t* tail = nullptr;
for(auto& version_report : version_reports) {
auto* node = new (std::nothrow) icsneoc2_chip_versions_t;
if(!node) {
icsneoc2_chip_versions_free(head);
return icsneoc2_error_out_of_memory;
}
node->version_report = version_report;
node->next = nullptr;
if(!head) {
head = node;
} else {
tail->next = node;
}
tail = node;
}
*chip_versions = head;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_chip_versions_free(icsneoc2_chip_versions_t* chip_versions) {
if(!chip_versions) {
return icsneoc2_error_invalid_parameters;
}
while(chip_versions) {
auto* next = chip_versions->next;
delete chip_versions;
chip_versions = next;
}
return icsneoc2_error_success;
}
icsneoc2_chip_versions_t* icsneoc2_chip_versions_next(const icsneoc2_chip_versions_t* chip_versions) {
if(!chip_versions) {
return nullptr;
}
return chip_versions->next;
}
icsneoc2_error_t icsneoc2_chip_versions_props_get(const icsneoc2_chip_versions_t* chip_versions, char* name, size_t* name_length, uint8_t* major, uint8_t* minor, uint8_t* maintenance, uint8_t* build) {
if(!chip_versions) {
return icsneoc2_error_invalid_parameters;
}
auto& report = chip_versions->version_report;
if(name && name_length) {
if(!safe_str_copy(name,name_length, report.name)) {
return icsneoc2_error_string_copy_failed;
}
}
if(major) {
*major = report.major;
}
if(minor) {
*minor = report.minor;
}
if(maintenance) {
*maintenance = report.maintenance;
}
if(build) {
*build = report.build;
}
return icsneoc2_error_success;
}
+21
View File
@@ -13,6 +13,11 @@
using namespace icsneo; using namespace icsneo;
typedef struct icsneoc2_supported_device_t {
DeviceType device_type;
icsneoc2_supported_device_t* next;
} icsneoc2_supported_device_t;
typedef struct icsneoc2_message_t { typedef struct icsneoc2_message_t {
std::shared_ptr<Message> message; std::shared_ptr<Message> message;
} icsneoc2_message_t; } icsneoc2_message_t;
@@ -38,6 +43,22 @@ typedef struct icsneoc2_script_status_t {
std::shared_ptr<ScriptStatusMessage> status; std::shared_ptr<ScriptStatusMessage> status;
} icsneoc2_script_status_t; } icsneoc2_script_status_t;
typedef struct icsneoc2_chip_versions_t {
VersionReport version_report;
icsneoc2_chip_versions_t* next;
} icsneoc2_chip_versions_t;
typedef struct icsneoc2_termination_group_t {
std::vector<icsneoc2_netid_t> netids;
icsneoc2_termination_group_t* next;
} icsneoc2_termination_group_t;
typedef struct icsneoc2_mac_addr_entry_t {
uint16_t network_id;
uint8_t address[ICSNEO_MAC_ADDRESS_LEN];
icsneoc2_mac_addr_entry_t* next;
} icsneoc2_mac_addr_entry_t;
/** /**
* Safely copies a std::string to a char array. * Safely copies a std::string to a char array.
* *
+95 -1
View File
@@ -7,8 +7,10 @@
#include "icsneo/communication/message/message.h" #include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/canerrormessage.h" #include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_message_t* message, bool* is_valid) { icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_message_t* message, bool* is_valid) {
@@ -126,6 +128,28 @@ icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_message_t* message, uint8_t*
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_message_timestamp_set(icsneoc2_message_t* message, uint64_t timestamp) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
if(!message->message) {
return icsneoc2_error_invalid_message;
}
message->message->timestamp = timestamp;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_timestamp_get(icsneoc2_message_t* message, uint64_t* timestamp) {
if(!message || !timestamp) {
return icsneoc2_error_invalid_parameters;
}
if(!message->message) {
return icsneoc2_error_invalid_message;
}
*timestamp = message->message->timestamp;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_message_t** message) { icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_message_t** message) {
if(!message) { if(!message) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
@@ -294,6 +318,44 @@ icsneoc2_error_t icsneoc2_message_can_error_props_get(
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_message_is_app_error(icsneoc2_message_t* message, bool* is_app_error) {
if(!message || !is_app_error) {
return icsneoc2_error_invalid_parameters;
}
*is_app_error = std::dynamic_pointer_cast<AppErrorMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_app_error_props_get(icsneoc2_message_t* message,
icsneoc2_app_error_type_t* error_type, icsneoc2_netid_t* error_netid) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto app_err = std::dynamic_pointer_cast<AppErrorMessage>(message->message);
if(!app_err) {
return icsneoc2_error_invalid_type;
}
if(error_type) {
*error_type = static_cast<icsneoc2_app_error_type_t>(app_err->getAppErrorType());
}
if(error_netid) {
*error_netid = static_cast<icsneoc2_netid_t>(app_err->errorNetID);
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_app_error_string_get(icsneoc2_message_t* message,
char* value, size_t* value_length) {
if(!message || !value_length) {
return icsneoc2_error_invalid_parameters;
}
auto app_err = std::dynamic_pointer_cast<AppErrorMessage>(message->message);
if(!app_err) {
return icsneoc2_error_invalid_type;
}
return safe_str_copy(value, value_length, app_err->getAppErrorString()) ? icsneoc2_error_success : icsneoc2_error_string_copy_failed;
}
icsneoc2_error_t icsneoc2_message_is_lin(icsneoc2_message_t* message, bool* is_lin) { icsneoc2_error_t icsneoc2_message_is_lin(icsneoc2_message_t* message, bool* is_lin) {
if(!message || !is_lin) { if(!message || !is_lin) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
@@ -409,6 +471,7 @@ icsneoc2_error_t icsneoc2_message_lin_status_flags_get(const icsneoc2_message_t*
if(lin_msg->statusFlags.HasUpdatedResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_HAS_UPDATED_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.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED;
if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY; if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY;
if(lin_msg->statusFlags.WakeupRequest) *status_flags |= ICSNEOC2_LIN_STATUS_WAKEUP_REQUEST;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
@@ -609,9 +672,40 @@ icsneoc2_error_t icsneoc2_message_eth_t1s_props_get(icsneoc2_message_t* message,
} }
icsneoc2_error_t icsneoc2_message_is_ethernet(icsneoc2_message_t* message, bool* is_ethernet) { icsneoc2_error_t icsneoc2_message_is_ethernet(icsneoc2_message_t* message, bool* is_ethernet) {
if(!message) { if(!message || !is_ethernet) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
} }
*is_ethernet = std::dynamic_pointer_cast<EthernetMessage>(message->message) != nullptr; *is_ethernet = std::dynamic_pointer_cast<EthernetMessage>(message->message) != nullptr;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_message_is_ethernet_status(icsneoc2_message_t* message, bool* is_ethernet_status) {
if(!message || !is_ethernet_status) {
return icsneoc2_error_invalid_parameters;
}
*is_ethernet_status = std::dynamic_pointer_cast<EthernetStatusMessage>(message->message) != nullptr;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_message_eth_status_props_get(icsneoc2_message_t* message, bool* link_state, bool* duplex, icsneoc2_link_speed_t* link_speed, icsneoc2_link_mode_t* link_mode) {
if(!message) {
return icsneoc2_error_invalid_parameters;
}
auto msg = std::dynamic_pointer_cast<EthernetStatusMessage>(message->message);
if(!msg) {
return icsneoc2_error_invalid_type;
}
if(link_state) {
*link_state = msg->state;
}
if(duplex) {
*duplex = msg->duplex;
}
if(link_speed) {
*link_speed = static_cast<icsneoc2_link_speed_t>(msg->speed);
}
if(link_mode) {
*link_mode = static_cast<icsneoc2_link_mode_t>(msg->mode);
}
return icsneoc2_error_success;
}
+300
View File
@@ -179,6 +179,82 @@ icsneoc2_error_t icsneoc2_settings_termination_set(icsneoc2_device_t* device, ic
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_termination_groups_enumerate(icsneoc2_device_t* device, icsneoc2_termination_group_t** groups, size_t* count) {
// Make sure the device is valid
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!groups) {
return icsneoc2_error_invalid_parameters;
}
auto termination_groups = device->device->settings->getTerminationGroups();
icsneoc2_termination_group_t* head = nullptr;
icsneoc2_termination_group_t* tail = nullptr;
for(const auto& group : termination_groups) {
auto* node = new (std::nothrow) icsneoc2_termination_group_t;
if(!node) {
icsneoc2_settings_termination_groups_free(head);
return icsneoc2_error_out_of_memory;
}
node->netids.reserve(group.size());
for(const auto& network : group) {
node->netids.push_back(static_cast<icsneoc2_netid_t>(network.getNetID()));
}
node->next = nullptr;
if(!head) {
head = node;
} else {
tail->next = node;
}
tail = node;
}
*groups = head;
if(count) {
*count = termination_groups.size();
}
return icsneoc2_error_success;
}
icsneoc2_termination_group_t* icsneoc2_termination_group_next(const icsneoc2_termination_group_t* group) {
if(!group) {
return nullptr;
}
return group->next;
}
icsneoc2_error_t icsneoc2_termination_group_networks_get(const icsneoc2_termination_group_t* group, icsneoc2_netid_t* networks, size_t* count) {
if(!group || !count) {
return icsneoc2_error_invalid_parameters;
}
if(!networks) {
*count = group->netids.size();
return icsneoc2_error_success;
}
size_t to_copy = std::min<size_t>(*count, group->netids.size());
for(size_t i = 0; i < to_copy; i++) {
networks[i] = group->netids[i];
}
*count = to_copy;
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_termination_groups_free(icsneoc2_termination_group_t* groups) {
if(!groups) {
return icsneoc2_error_invalid_parameters;
}
while(groups) {
auto* next = groups->next;
delete groups;
groups = next;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_commander_resistor_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) { icsneoc2_error_t icsneoc2_settings_commander_resistor_enabled(icsneoc2_device_t* device, icsneoc2_netid_t netid, bool* enabled) {
// Make sure the device is valid // Make sure the device is valid
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
@@ -867,6 +943,120 @@ icsneoc2_error_t icsneoc2_settings_misc_io_analog_output_set(icsneoc2_device_t*
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_linux_boot_enabled_get(icsneoc2_device_t* device, 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->getLinuxBootEnabled(); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_linux_boot_enabled_set(icsneoc2_device_t* device, 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->setLinuxBootEnabled(value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_external_wifi_antenna_enabled_get(icsneoc2_device_t* device, 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->getExternalWifiAntennaEnabled(); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_external_wifi_antenna_enabled_set(icsneoc2_device_t* device, 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->setExternalWifiAntennaEnabled(value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_perf_test_enabled_get(icsneoc2_device_t* device, 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->isPerfTestEnabled(); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
} else {
*value = false;
return icsneoc2_error_get_settings_failure;
}
}
icsneoc2_error_t icsneoc2_settings_perf_test_enabled_set(icsneoc2_device_t* device, 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->setPerfTestEnable(value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_linux_configuration_port_get(icsneoc2_device_t* device, icsneoc2_linux_configuration_port_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->getLinuxConfigurationPort(); result.has_value()) {
*value = static_cast<icsneoc2_linux_configuration_port_t>(result.value());
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_linux_configuration_port_set(icsneoc2_device_t* device, icsneoc2_linux_configuration_port_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->setLinuxConfigurationPort(static_cast<LinuxConfigurationPort>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_disabled_get(icsneoc2_device_t* device, bool* value) { icsneoc2_error_t icsneoc2_settings_disabled_get(icsneoc2_device_t* device, bool* value) {
if(!value) { if(!value) {
return icsneoc2_error_invalid_parameters; return icsneoc2_error_invalid_parameters;
@@ -892,3 +1082,113 @@ icsneoc2_error_t icsneoc2_settings_readonly_get(icsneoc2_device_t* device, bool*
*value = device->device->settings->readonly; *value = device->device->settings->readonly;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_settings_gptp_profile_get(icsneoc2_device_t* device, icsneoc2_gptp_profile_t* value) {
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->getGPTPProfile(); result.has_value()) {
*value = static_cast<icsneoc2_gptp_profile_t>(result.value());
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_gptp_profile_set(icsneoc2_device_t* device, icsneoc2_gptp_profile_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(value >= icsneoc2_gptp_profile_maxsize) {
return icsneoc2_error_invalid_parameters;
}
if(!device->device->settings->setGPTPProfile(static_cast<RADGPTPProfile>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_gptp_role_get(icsneoc2_device_t* device, icsneoc2_gptp_role_t* value) {
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->getGPTPRole(); result.has_value()) {
*value = static_cast<icsneoc2_gptp_role_t>(result.value());
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_gptp_role_set(icsneoc2_device_t* device, icsneoc2_gptp_role_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(value >= icsneoc2_gptp_role_maxsize) {
return icsneoc2_error_invalid_parameters;
}
if(!device->device->settings->setGPTPRole(static_cast<RADGPTPRole>(value))) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_gptp_enabled_port_get(icsneoc2_device_t* device, uint8_t* value) {
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->getGPTPEnabledPort(); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_gptp_enabled_port_set(icsneoc2_device_t* device, uint8_t value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setGPTPEnabledPort(value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_settings_gptp_clock_syntonization_enabled_get(icsneoc2_device_t* device, bool* value) {
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->isGPTPClockSyntonizationEnabled(); result.has_value()) {
*value = result.value();
return icsneoc2_error_success;
}
return icsneoc2_error_get_settings_failure;
}
icsneoc2_error_t icsneoc2_settings_gptp_clock_syntonization_enabled_set(icsneoc2_device_t* device, bool value) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->settings->setGPTPClockSyntonizationEnabled(value)) {
return icsneoc2_error_set_settings_failure;
}
return icsneoc2_error_success;
}
+14 -10
View File
@@ -4,10 +4,10 @@
using namespace icsneo; using namespace icsneo;
APIEvent::APIEvent(Type type, APIEvent::Severity severity, const Device* device) : eventStruct({}) { APIEvent::APIEvent(Type type, APIEvent::Severity severity, std::weak_ptr<Device> device) : eventStruct({}), device(device) {
this->device = device; auto shared = device.lock();
if(device) { if(shared) {
serial = device->getSerial(); serial = shared->getSerial();
eventStruct.serial[serial.copy(eventStruct.serial, sizeof(eventStruct.serial))] = '\0'; eventStruct.serial[serial.copy(eventStruct.serial, sizeof(eventStruct.serial))] = '\0';
} }
@@ -27,9 +27,10 @@ void APIEvent::downgradeFromError() noexcept {
} }
bool APIEvent::isForDevice(std::string filterSerial) const noexcept { bool APIEvent::isForDevice(std::string filterSerial) const noexcept {
if(!device || filterSerial.length() == 0) auto shared = device.lock();
if(!shared || filterSerial.length() == 0)
return false; return false;
return device->getSerial() == filterSerial; return shared->getSerial() == filterSerial;
} }
// API Errors // API Errors
@@ -63,8 +64,8 @@ static constexpr const char* NO_SERIAL_NUMBER_12V = "Communication could not be
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy."; static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered or requires a firmware update using Vehicle Spy.";
static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!"; static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* SETTINGS_READ = "The device settings could not be read."; static constexpr const char* SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer."; static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with ICS Device Manager.";
static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer."; static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with ICS Device Manager.";
static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue."; static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device."; static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device."; static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device.";
@@ -461,14 +462,17 @@ const char* APIEvent::DescriptionForType(Type type) {
return TOO_MANY_EVENTS; return TOO_MANY_EVENTS;
case Type::Unknown: case Type::Unknown:
return UNKNOWN; return UNKNOWN;
case Type::Any:
break;
} }
return INVALID; return INVALID;
} }
std::string APIEvent::describe() const noexcept { std::string APIEvent::describe() const noexcept {
std::stringstream ss; std::stringstream ss;
if(device) auto shared = device.lock();
ss << *device; // Makes use of device.describe() if(shared)
ss << *shared; // Makes use of device.describe()
else else
ss << "API"; ss << "API";
+2 -2
View File
@@ -7,8 +7,8 @@
using namespace icsneo; using namespace icsneo;
EventManager& EventManager::GetInstance() { EventManager& EventManager::GetInstance() {
static EventManager inst; static EventManager* inst = new EventManager();
return inst; return *inst;
} }
void EventManager::downgradeErrorsOnCurrentThread() { void EventManager::downgradeErrorsOnCurrentThread() {
+60
View File
@@ -0,0 +1,60 @@
#include "icsneo/api/heartbeat.h"
#include "icsneo/api/lifetime.h"
#include "icsneo/device/device.h"
using namespace icsneo;
Heartbeat::Heartbeat(Device& device) :
device(device), mode(device.isOnline() ? Mode::Passive : Mode::Active), thread(&Heartbeat::run, this) {
}
Heartbeat::~Heartbeat() {
{
std::lock_guard lk(mutex);
stop = true;
}
cv.notify_one();
thread.join();
}
void Heartbeat::run() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
auto filter = std::make_shared<MessageFilter>();
filter->includeInternalInAny = true;
bool status = false;
auto cbHandle = device.com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message> msg) {
// TODO: remove DeviceStatus after 2027-08-17, as ResetStatus should be widely supported
const bool isHeartbeat =
(msg->type == Message::Type::ResetStatus) ||
(msg->type == Message::Type::RawMessage && std::static_pointer_cast<RawMessage>(msg)->network == Network::NetID::DeviceStatus);
if(!isHeartbeat)
return;
{
std::lock_guard lk(mutex);
status = true;
}
cv.notify_one();
}));
Lifetime cbLifetime([&] {
device.com->removeMessageCallback(cbHandle);
});
while(true) {
std::unique_lock lk(mutex);
if(mode == Mode::Active) {
if(cv.wait_for(lk, std::chrono::milliseconds(100), [&] { return stop; })) {
break;
}
device.com->sendCommand(Command::RequestStatusUpdate);
}
if(!cv.wait_for(lk, std::chrono::seconds(2), [&] { return status || stop; })) {
// we disconnect instead of close because it indicates to the user that a cleanup is still required (our thread join)
device.report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
device.com->driver->setIsDisconnected(true);
break;
}
if(stop)
break;
status = false;
}
}
@@ -5,6 +5,13 @@
#include <windows.h> #include <windows.h>
#include "icsneo/icsnVC40.h" #include "icsneo/icsnVC40.h"
// Vehicle Spy 3.26.3.9 removed these legacy settings structure definitions from
// icsnVC40.h. The corresponding functions only ever treat them as opaque
// buffers, so forward declarations keep the existing API/ABI intact.
typedef struct _SFireSettings SFireSettings;
typedef struct _SVCAN3Settings SVCAN3Settings;
typedef struct _SVCANRFSettings SVCANRFSettings;
bool LoadDLLAPI(HINSTANCE &hAPIDLL); bool LoadDLLAPI(HINSTANCE &hAPIDLL);
+28 -30
View File
@@ -545,15 +545,13 @@ int LegacyDLLExport icsneoGetTimeStampForMsg(void* hObject, icsSpyMessage* pMsg,
void LegacyDLLExport icsneoGetISO15765Status(void* hObject, int lNetwork, int lClearTxStatus, int lClearRxStatus, void LegacyDLLExport icsneoGetISO15765Status(void* hObject, int lNetwork, int lClearTxStatus, int lClearRxStatus,
int* lTxStatus, int* lRxStatus) int* lTxStatus, int* lRxStatus)
{ {
// TODO Implement // Not supported
return;
} }
void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork, int lEnable, spyFilterLong* pFF_CFMsgFilter, void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork, int lEnable, spyFilterLong* pFF_CFMsgFilter,
icsSpyMessage* pTxMsg, int lCFTimeOutMs, int lFlowCBlockSize, int lUsesExtendedAddressing, int lUseHardwareIfPresent) icsSpyMessage* pTxMsg, int lCFTimeOutMs, int lFlowCBlockSize, int lUsesExtendedAddressing, int lUseHardwareIfPresent)
{ {
// TODO Implement // Not supported
return;
} }
int LegacyDLLExport icsneoGetRTC(void* hObject, icsSpyTime* time) int LegacyDLLExport icsneoGetRTC(void* hObject, icsSpyTime* time)
@@ -835,26 +833,25 @@ int LegacyDLLExport icsneoGetErrorInfo(int lErrorNumber, char* szErrorDescriptio
//ISO15765-2 Functions //ISO15765-2 Functions
int LegacyDLLExport icsneoISO15765_EnableNetworks(void* hObject, unsigned long ulNetworks) int LegacyDLLExport icsneoISO15765_EnableNetworks(void* hObject, unsigned long ulNetworks)
{ {
// TODO Implement // Not supported
return false; return false;
} }
int LegacyDLLExport icsneoISO15765_DisableNetworks(void* hObject) int LegacyDLLExport icsneoISO15765_DisableNetworks(void* hObject)
{ {
// TODO Implement // Not supported
return false; return false;
} }
int LegacyDLLExport icsneoISO15765_TransmitMessage(void* hObject, unsigned long ulNetworkID, stCM_ISO157652_TxMessage* pMsg, int LegacyDLLExport icsneoISO15765_TransmitMessage(void* hObject, unsigned long ulNetworkID, stCM_ISO157652_TxMessage* pMsg, unsigned long ulBlockingTimeout)
unsigned long ulBlockingTimeout)
{ {
// TODO Implement // Not supported
return false; return false;
} }
int LegacyDLLExport icsneoISO15765_ReceiveMessage(void* hObject, int ulNetworkID, stCM_ISO157652_RxMessage* pMsg) int LegacyDLLExport icsneoISO15765_ReceiveMessage(void* hObject, int ulNetworkID, stCM_ISO157652_RxMessage* pMsg)
{ {
// TODO Implement // Not supported
return false; return false;
} }
@@ -1035,10 +1032,10 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_ION: case NEODEVICE_ION:
*pDeviceSettingsType = DeviceFire2SettingsType; //defaults to FIRE2 vnets with libicsneo - no firevnets! *pDeviceSettingsType = DeviceFire2SettingsType; //defaults to FIRE2 vnets with libicsneo - no firevnets!
break; break;
case NEODEVICE_VCAN3: case NEODEVICE_VCAN3_DEPRECATED:
*pDeviceSettingsType = DeviceVCAN3SettingsType; *pDeviceSettingsType = DeviceVCAN3SettingsTypeDeprecated;
break; break;
case NEODEVICE_FIRE: case NEODEVICE_FIRE_DEPRECATED:
*pDeviceSettingsType = DeviceFireSettingsType; *pDeviceSettingsType = DeviceFireSettingsType;
break; break;
case NEODEVICE_FIRE2: case NEODEVICE_FIRE2:
@@ -1061,17 +1058,17 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_VIVIDCAN: case NEODEVICE_VIVIDCAN:
*pDeviceSettingsType = DeviceVividCANSettingsType; *pDeviceSettingsType = DeviceVividCANSettingsType;
break; break;
case NEODEVICE_ECU_AVB: case NEODEVICE_ECU_AVB_DEPRECATED:
*pDeviceSettingsType = DeviceECU_AVBSettingsType; *pDeviceSettingsType = DeviceECU_AVBSettingsTypeDeprecated;
break; break;
case NEODEVICE_RADSUPERMOON: case NEODEVICE_RADSUPERMOON_DEPRECATED:
*pDeviceSettingsType = DeviceRADSuperMoonSettingsType; *pDeviceSettingsType = DeviceRADSuperMoonSettingsTypeDeprecated;
break; break;
case NEODEVICE_RADMOON2: case NEODEVICE_RADMOON2:
*pDeviceSettingsType = DeviceRADMoon2SettingsType; *pDeviceSettingsType = DeviceRADMoon2SettingsType;
break; break;
case NEODEVICE_RADGIGALOG: case NEODEVICE_RADGIGALOG_DEPRECATED:
*pDeviceSettingsType = DeviceRADGigalogSettingsType; *pDeviceSettingsType = DeviceRADGigalogSettingsTypeDeprecated;
break; break;
case NEODEVICE_RADMOON3: case NEODEVICE_RADMOON3:
*pDeviceSettingsType = DeviceRADMoon3SettingsType; *pDeviceSettingsType = DeviceRADMoon3SettingsType;
@@ -1088,6 +1085,8 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_FIRE3_FLEXRAY: case NEODEVICE_FIRE3_FLEXRAY:
*pDeviceSettingsType = DeviceFire3FlexraySettingsType; *pDeviceSettingsType = DeviceFire3FlexraySettingsType;
break; break;
case NEODEVICE_RAD_BMS:
*pDeviceSettingsType = DeviceRADBMSSettingsType;
default: default:
return 0; return 0;
} }
@@ -1283,10 +1282,11 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
return false; return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject); neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
const auto& cmd = static_cast<icsneo::J2534Command>(*CmdBuf);
switch (*CmdBuf) switch (cmd)
{ {
case J2534NVCMD_SetNetworkBaudRate: case icsneo::J2534Command::SetNetworkBaudRate:
pTmp = (uint64_t *)&CmdBuf[1]; pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp; NetworkID = (uint16_t)*pTmp;
@@ -1296,7 +1296,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
iRetVal = 0; iRetVal = 0;
break; break;
case J2534NVCMD_GetNetworkBaudRate: case icsneo::J2534Command::GetNetworkBaudRate:
{ {
pTmp = (uint64_t *)&CmdBuf[1]; pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp; NetworkID = (uint16_t)*pTmp;
@@ -1309,7 +1309,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
*pTmp = static_cast<uint64_t>(ret); *pTmp = static_cast<uint64_t>(ret);
break; break;
} }
case J2534NVCMD_SetCANFDRate: case icsneo::J2534Command::SetCANFDRate:
pTmp = (uint64_t *)&CmdBuf[1]; pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp; NetworkID = (uint16_t)*pTmp;
@@ -1320,7 +1320,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
iRetVal = 0; iRetVal = 0;
break; break;
case J2534NVCMD_GetCANFDRate: case icsneo::J2534Command::GetCANFDRate:
pTmp = (uint64_t *)&CmdBuf[1]; pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp; NetworkID = (uint16_t)*pTmp;
@@ -1330,7 +1330,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
*pTmp = icsneo_getFDBaudrate(device, NetworkID); *pTmp = icsneo_getFDBaudrate(device, NetworkID);
break; break;
case J2534NVCMD_GetCANFDTermination: case icsneo::J2534Command::GetCANFDTermination:
pTmp = (uint64_t *)&CmdBuf[1]; pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp; NetworkID = (uint16_t)*pTmp;
@@ -1366,7 +1366,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
} }
break; break;
case J2534NVCMD_SetCANFDTermination: case icsneo::J2534Command::SetCANFDTermination:
pTmp = (uint64_t *)&CmdBuf[1]; pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp; NetworkID = (uint16_t)*pTmp;
@@ -1420,11 +1420,9 @@ int LegacyDLLExport icsneoEnableBusVoltageMonitor(void* hObject, unsigned int en
return false; return false;
} }
int LegacyDLLExport icsneoISO15765_TransmitMessageEx(void* hObject, int LegacyDLLExport icsneoISO15765_TransmitMessageEx(void* hObject, unsigned long ulNetworkID, ISO15765_2015_TxMessage* pMsg, unsigned long ulBlockingTimeout)
unsigned long ulNetworkID,
ISO15765_2015_TxMessage* pMsg,
unsigned long ulBlockingTimeout)
{ {
// Not supported
return false; return false;
} }
+13 -1
View File
@@ -31,6 +31,8 @@ pybind11_add_module(icsneopy
icsneopy/communication/message/tc10statusmessage.cpp icsneopy/communication/message/tc10statusmessage.cpp
icsneopy/communication/message/mdiomessage.cpp icsneopy/communication/message/mdiomessage.cpp
icsneopy/communication/message/gptpstatusmessage.cpp icsneopy/communication/message/gptpstatusmessage.cpp
icsneopy/communication/message/allmacaddressesmessage.cpp
icsneopy/communication/message/apperrormessage.cpp
icsneopy/communication/message/ethernetstatusmessage.cpp icsneopy/communication/message/ethernetstatusmessage.cpp
icsneopy/communication/message/spimessage.cpp icsneopy/communication/message/spimessage.cpp
icsneopy/communication/message/scriptstatusmessage.cpp icsneopy/communication/message/scriptstatusmessage.cpp
@@ -38,6 +40,9 @@ pybind11_add_module(icsneopy
icsneopy/communication/message/livedatamessage.cpp icsneopy/communication/message/livedatamessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/communication/message/filter/main51messagefilter.cpp
icsneopy/communication/message/main51message.cpp
icsneopy/communication/command.cpp
icsneopy/core/macseccfg.cpp icsneopy/core/macseccfg.cpp
icsneopy/flexray/flexray.cpp icsneopy/flexray/flexray.cpp
icsneopy/disk/diskdriver.cpp icsneopy/disk/diskdriver.cpp
@@ -55,7 +60,14 @@ install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN_EXE stubgen) find_program(STUBGEN_EXE stubgen)
if(STUBGEN_EXE) if(STUBGEN_EXE)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND stubgen -v -p icsneopy -o .) # Multi-config generators put the extension in Release/ or Debug/. Import
# that freshly built module, not a globally installed older icsneopy.
add_custom_command(TARGET icsneopy POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E rm -f "${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi"
COMMAND "${STUBGEN_EXE}" -v -p icsneopy -o "${CMAKE_CURRENT_BINARY_DIR}"
WORKING_DIRECTORY "$<TARGET_FILE_DIR:icsneopy>"
VERBATIM
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi py.typed DESTINATION icsneopy) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi py.typed DESTINATION icsneopy)
endif() endif()
@@ -0,0 +1,40 @@
#include <pybind11/pybind11.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/command.h"
namespace icsneo {
void init_command(pybind11::module_& m) {
pybind11::native_enum<Command>(m, "Command", "enum.IntEnum")
.value("Main51RxBufferOverflow", Command::Main51RxBufferOverflow)
.value("Main51StartCmd", Command::Main51StartCmd)
.value("Main51TxFifoOverflow", Command::Main51TxFifoOverflow)
.value("Main51BulkInNoData", Command::Main51BulkInNoData)
.value("Main51SetModeComplete", Command::Main51SetModeComplete)
.value("Main51ReadEeprom", Command::Main51ReadEeprom)
.value("Main51CmdDone", Command::Main51CmdDone)
.value("Main51ErrStatus", Command::Main51ErrStatus)
.value("Main51ReadSectorBuff", Command::Main51ReadSectorBuff)
.value("Main51WriteSectorBuff", Command::Main51WriteSectorBuff)
.value("Main51MmcProcessDone", Command::Main51MmcProcessDone)
.value("Main51ReInitDone", Command::Main51ReInitDone)
.value("EnableNetworkCommunication", Command::EnableNetworkCommunication)
.value("EnableNetworkCommunicationEx", Command::EnableNetworkCommunicationEx)
.value("KeepAlive", Command::KeepAlive)
.value("RequestSerialNumber", Command::RequestSerialNumber)
.value("GetMainVersion", Command::GetMainVersion)
.value("SetSettings", Command::SetSettings)
.value("SaveSettings", Command::SaveSettings)
.value("SetDefaultSettings", Command::SetDefaultSettings)
.value("ReadSettings", Command::ReadSettings)
.value("ScriptStatus", Command::ScriptStatus)
.value("WiVICommand", Command::WiVICommand)
.value("Extended", Command::Extended)
.value("ExtendedData", Command::ExtendedData)
.value("FlexRayControl", Command::FlexRayControl)
.value("CoreMiniPreload", Command::CoreMiniPreload)
.finalize();
}
} // namespace icsneo
@@ -0,0 +1,13 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "icsneo/communication/message/allmacaddressesmessage.h"
namespace icsneo {
void init_allmacaddressesmessage(pybind11::module_& m) {
pybind11::classh<AllMACAddressesMessage, Message>(m, "AllMACAddressesMessage")
.def_readonly("addresses", &AllMACAddressesMessage::addresses);
}
} // namespace icsneo
@@ -0,0 +1,71 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/message/apperrormessage.h"
namespace icsneo {
void init_errortypes(pybind11::module_& m) {
pybind11::native_enum<AppErrorType>(m, "AppErrorType", "enum.IntEnum")
.value("RxMessagesFull", AppErrorType::AppErrorRxMessagesFull)
.value("TxMessagesFull", AppErrorType::AppErrorTxMessagesFull)
.value("TxReportMessagesFull", AppErrorType::AppErrorTxReportMessagesFull)
.value("BadCommWithDspIC", AppErrorType::AppErrorBadCommWithDspIC)
.value("DriverOverflow", AppErrorType::AppErrorDriverOverflow)
.value("PCBuffOverflow", AppErrorType::AppErrorPCBuffOverflow)
.value("PCChksumError", AppErrorType::AppErrorPCChksumError)
.value("PCMissedByte", AppErrorType::AppErrorPCMissedByte)
.value("PCOverrunError", AppErrorType::AppErrorPCOverrunError)
.value("SettingFailure", AppErrorType::AppErrorSettingFailure)
.value("TooManySelectedNetworks", AppErrorType::AppErrorTooManySelectedNetworks)
.value("NetworkNotEnabled", AppErrorType::AppErrorNetworkNotEnabled)
.value("RtcNotCorrect", AppErrorType::AppErrorRtcNotCorrect)
.value("LoadedDefaultSettings", AppErrorType::AppErrorLoadedDefaultSettings)
.value("FeatureNotUnlocked", AppErrorType::AppErrorFeatureNotUnlocked)
.value("FeatureRtcCmdDropped", AppErrorType::AppErrorFeatureRtcCmdDropped)
.value("TxMessagesFlushed", AppErrorType::AppErrorTxMessagesFlushed)
.value("TxMessagesHalfFull", AppErrorType::AppErrorTxMessagesHalfFull)
.value("NetworkNotValid", AppErrorType::AppErrorNetworkNotValid)
.value("TxInterfaceNotImplemented", AppErrorType::AppErrorTxInterfaceNotImplemented)
.value("TxMessagesCommEnableIsOff", AppErrorType::AppErrorTxMessagesCommEnableIsOff)
.value("RxFilterMatchCountExceeded", AppErrorType::AppErrorRxFilterMatchCountExceeded)
.value("EthPreemptionNotEnabled", AppErrorType::AppErrorEthPreemptionNotEnabled)
.value("TxNotSupportedInMode", AppErrorType::AppErrorTxNotSupportedInMode)
.value("JumboFramesNotSupported", AppErrorType::AppErrorJumboFramesNotSupported)
.value("EthernetIpFragment", AppErrorType::AppErrorEthernetIpFragment)
.value("TxMessagesUnderrun", AppErrorType::AppErrorTxMessagesUnderrun)
.value("DeviceFanFailure", AppErrorType::AppErrorDeviceFanFailure)
.value("DeviceOvertemperature", AppErrorType::AppErrorDeviceOvertemperature)
.value("TxMessageIndexOutOfRange", AppErrorType::AppErrorTxMessageIndexOutOfRange)
.value("UndersizedFrameDropped", AppErrorType::AppErrorUndersizedFrameDropped)
.value("OversizedFrameDropped", AppErrorType::AppErrorOversizedFrameDropped)
.value("WatchdogEvent", AppErrorType::AppErrorWatchdogEvent)
.value("SystemClockFailure", AppErrorType::AppErrorSystemClockFailure)
.value("SystemClockRecovered", AppErrorType::AppErrorSystemClockRecovered)
.value("SystemPeripheralReset", AppErrorType::AppErrorSystemPeripheralReset)
.value("SystemCommunicationFailure", AppErrorType::AppErrorSystemCommunicationFailure)
.value("TxMessagesUnsupportedSourceOrPacketId", AppErrorType::AppErrorTxMessagesUnsupportedSourceOrPacketId)
.value("WbmsManagerConnectFailed", AppErrorType::AppErrorWbmsManagerConnectFailed)
.value("WbmsManagerConnectBadState", AppErrorType::AppErrorWbmsManagerConnectBadState)
.value("WbmsManagerConnectTimeout", AppErrorType::AppErrorWbmsManagerConnectTimeout)
.value("FailedToInitializeLoggerDisk", AppErrorType::AppErrorFailedToInitializeLoggerDisk)
.value("InvalidSetting", AppErrorType::AppErrorInvalidSetting)
.value("SystemFailureRequestedReset", AppErrorType::AppErrorSystemFailureRequestedReset)
.value("PortKeyMistmatch", AppErrorType::AppErrorPortKeyMistmatch)
.value("BusFailure", AppErrorType::AppErrorBusFailure)
.value("TapOverflow", AppErrorType::AppErrorTapOverflow)
.value("EthTxNoLink", AppErrorType::AppErrorEthTxNoLink)
.value("ErrorBufferOverflow", AppErrorType::AppErrorErrorBufferOverflow)
.value("NoError", AppErrorType::AppNoError)
.finalize();
}
void init_apperrormessage(pybind11::module_& m) {
init_errortypes(m);
pybind11::classh<AppErrorMessage, Message>(m, "AppErrorMessage")
.def("get_app_error_type", &AppErrorMessage::getAppErrorType)
.def("get_app_error_string", &AppErrorMessage::getAppErrorString);
}
} // namespace icsneo
@@ -7,7 +7,7 @@
namespace icsneo { namespace icsneo {
void init_ethernetstatusmessage(pybind11::module_& m) { void init_ethernetstatusmessage(pybind11::module_& m) {
pybind11::classh<EthernetStatusMessage, Message> ethernetStatusMessage(m, "EthernetStatusMessage"); pybind11::classh<EthernetStatusMessage, RawMessage> ethernetStatusMessage(m, "EthernetStatusMessage");
pybind11::enum_<EthernetStatusMessage::LinkSpeed>(ethernetStatusMessage, "LinkSpeed") pybind11::enum_<EthernetStatusMessage::LinkSpeed>(ethernetStatusMessage, "LinkSpeed")
.value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto) .value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto)
@@ -0,0 +1,13 @@
#include <pybind11/pybind11.h>
#include "icsneo/communication/message/filter/main51messagefilter.h"
namespace icsneo {
void init_main51messagefilter(pybind11::module_& m) {
pybind11::classh<Main51MessageFilter, MessageFilter>(m, "Main51MessageFilter")
.def(pybind11::init<>())
.def(pybind11::init<Command>());
}
} // namespace icsneo
@@ -28,7 +28,8 @@ void init_linmessage(pybind11::module_& m) {
.def_readwrite("UpdateResponderOnce", &LINStatusFlags::UpdateResponderOnce) .def_readwrite("UpdateResponderOnce", &LINStatusFlags::UpdateResponderOnce)
.def_readwrite("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce) .def_readwrite("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce)
.def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered) .def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered)
.def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly); .def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly)
.def_readwrite("WakeupRequest", &LINStatusFlags::WakeupRequest);
pybind11::classh<LINMessage, Frame> linMessage(m, "LINMessage"); pybind11::classh<LINMessage, Frame> linMessage(m, "LINMessage");
@@ -39,7 +40,8 @@ void init_linmessage(pybind11::module_& m) {
.value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY) .value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY)
.value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY) .value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY)
.value("LIN_UPDATE_RESPONDER", LINMessage::Type::LIN_UPDATE_RESPONDER) .value("LIN_UPDATE_RESPONDER", LINMessage::Type::LIN_UPDATE_RESPONDER)
.value("LIN_ERROR", LINMessage::Type::LIN_ERROR); .value("LIN_ERROR", LINMessage::Type::LIN_ERROR)
.value("LIN_WAKEUP_REQUEST", LINMessage::Type::LIN_WAKEUP_REQUEST);
linMessage linMessage
.def(pybind11::init<>()) .def(pybind11::init<>())
@@ -0,0 +1,13 @@
#include <pybind11/pybind11.h>
#include "icsneo/communication/message/main51message.h"
namespace icsneo {
void init_main51message(pybind11::module_& m) {
pybind11::classh<Main51Message, RawMessage>(m, "Main51Message")
.def(pybind11::init<>())
.def_readonly("command", &Main51Message::command);
}
} // namespace icsneo
+1 -1
View File
@@ -120,7 +120,7 @@ void init_chipid(pybind11::module_& m) {
.value("VEM_01_8DW_ZCHIP", ChipID::VEM_01_8DW_ZCHIP) .value("VEM_01_8DW_ZCHIP", ChipID::VEM_01_8DW_ZCHIP)
.value("RADGalaxy_FFG_Zynq", ChipID::RADGalaxy_FFG_Zynq) .value("RADGalaxy_FFG_Zynq", ChipID::RADGalaxy_FFG_Zynq)
.value("RADMoon3_MCHIP", ChipID::RADMoon3_MCHIP) .value("RADMoon3_MCHIP", ChipID::RADMoon3_MCHIP)
.value("RADComet_ZYNQ", ChipID::RADComet_ZYNQ) .value("RADComet2_ZYNQ", ChipID::RADComet2_ZYNQ)
.value("VEM_02_FR_ZCHIP", ChipID::VEM_02_FR_ZCHIP) .value("VEM_02_FR_ZCHIP", ChipID::VEM_02_FR_ZCHIP)
.value("RADA2B_REVB_ZCHIP", ChipID::RADA2B_REVB_ZCHIP) .value("RADA2B_REVB_ZCHIP", ChipID::RADA2B_REVB_ZCHIP)
.value("RADGigastar_FFG_ZYNQ", ChipID::RADGigastar_FFG_ZYNQ) .value("RADGigastar_FFG_ZYNQ", ChipID::RADGigastar_FFG_ZYNQ)
+3 -1
View File
@@ -33,7 +33,7 @@ void init_device(pybind11::module_& m) {
.def("get_serial_number", &Device::getSerialNumber) .def("get_serial_number", &Device::getSerialNumber)
.def("get_serial", &Device::getSerial) .def("get_serial", &Device::getSerial)
.def("get_pcb_serial", &Device::getPCBSerial, pybind11::call_guard<pybind11::gil_scoped_release>()) .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_mac_addresses", &Device::getMACAddresses, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference) .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_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference)
.def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>())
@@ -52,9 +52,11 @@ void init_device(pybind11::module_& m) {
.def("set_digital_io", pybind11::overload_cast<IO, size_t, bool>(&Device::setDigitalIO), pybind11::arg("type"), pybind11::arg("number"), pybind11::arg("value"), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("set_digital_io", pybind11::overload_cast<IO, size_t, bool>(&Device::setDigitalIO), pybind11::arg("type"), pybind11::arg("number"), pybind11::arg("value"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_polling_message_limit", &Device::setPollingMessageLimit) .def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("reboot", &Device::reboot, pybind11::arg("safe") = false, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("start_script", &Device::startScript, pybind11::call_guard<pybind11::gil_scoped_release>()) .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("stop_script", &Device::stopScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_tc10", &Device::supportsTC10) .def("supports_tc10", &Device::supportsTC10)
.def("supports_reboot", &Device::supportsReboot)
.def("supports_live_data", &Device::supportsLiveData) .def("supports_live_data", &Device::supportsLiveData)
.def("subscribe_live_data", &Device::subscribeLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>()) .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("unsubscribe_live_data", &Device::unsubscribeLiveData, pybind11::arg("handle"), pybind11::call_guard<pybind11::gil_scoped_release>())
@@ -36,9 +36,10 @@ void init_devicetype(pybind11::module_& m) {
.value("RADEpsilon", DeviceType::Enum::RADEpsilon) .value("RADEpsilon", DeviceType::Enum::RADEpsilon)
.value("RADEpsilonXL", DeviceType::Enum::RADEpsilonXL) .value("RADEpsilonXL", DeviceType::Enum::RADEpsilonXL)
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2) .value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADwBMS", DeviceType::Enum::RADwBMS)
.value("RADMoon3", DeviceType::Enum::RADMoon3) .value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADGemini", DeviceType::Enum::RADGemini) .value("RADGemini", DeviceType::Enum::RADGemini)
.value("RADComet", DeviceType::Enum::RADComet) .value("RADComet2", DeviceType::Enum::RADComet2)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay) .value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("FIRE3_T1S_LIN", DeviceType::Enum::FIRE3_T1S_LIN) .value("FIRE3_T1S_LIN", DeviceType::Enum::FIRE3_T1S_LIN)
.value("FIRE3_T1S_SENT", DeviceType::Enum::FIRE3_T1S_SENT) .value("FIRE3_T1S_SENT", DeviceType::Enum::FIRE3_T1S_SENT)
@@ -40,6 +40,16 @@ void init_idevicesettings(pybind11::module_& m) {
.value("Normal", LINMode::NORMAL_MODE) .value("Normal", LINMode::NORMAL_MODE)
.value("Fast", LINMode::FAST_MODE); .value("Fast", LINMode::FAST_MODE);
pybind11::enum_<RADGPTPProfile>(settings, "GPTPProfile")
.value("Standard", RADGPTPProfile::RAD_GPTP_PROFILE_STANDARD)
.value("Automotive", RADGPTPProfile::RAD_GPTP_PROFILE_AUTOMOTIVE);
pybind11::enum_<RADGPTPRole>(settings, "GPTPRole")
.value("Disabled", RADGPTPRole::RAD_GPTP_ROLE_DISABLED)
.value("Passive", RADGPTPRole::RAD_GPTP_ROLE_PASSIVE)
.value("Master", RADGPTPRole::RAD_GPTP_ROLE_MASTER)
.value("Slave", RADGPTPRole::RAD_GPTP_ROLE_SLAVE);
pybind11::enum_<MiscIOAnalogVoltage>(settings, "MiscIOAnalogVoltage") pybind11::enum_<MiscIOAnalogVoltage>(settings, "MiscIOAnalogVoltage")
.value("V0", MiscIOAnalogVoltage::V0) .value("V0", MiscIOAnalogVoltage::V0)
.value("V1", MiscIOAnalogVoltage::V1) .value("V1", MiscIOAnalogVoltage::V1)
@@ -48,6 +58,10 @@ void init_idevicesettings(pybind11::module_& m) {
.value("V4", MiscIOAnalogVoltage::V4) .value("V4", MiscIOAnalogVoltage::V4)
.value("V5", MiscIOAnalogVoltage::V5); .value("V5", MiscIOAnalogVoltage::V5);
pybind11::enum_<LinuxConfigurationPort>(settings, "LinuxConfigurationPort")
.value("USB", LinuxConfigurationPort::USB)
.value("ETH01", LinuxConfigurationPort::ETH01);
pybind11::classh<IDeviceSettings>(m, "IDeviceSettings") pybind11::classh<IDeviceSettings>(m, "IDeviceSettings")
.def("apply", &IDeviceSettings::apply, pybind11::arg("temporary") = 0, pybind11::call_guard<pybind11::gil_scoped_release>()) .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("apply_defaults", &IDeviceSettings::applyDefaults, pybind11::arg("temporary") = 0, pybind11::call_guard<pybind11::gil_scoped_release>())
@@ -119,7 +133,28 @@ void init_idevicesettings(pybind11::module_& m) {
.def("set_misc_io_analog_output_enabled", &IDeviceSettings::setMiscIOAnalogOutputEnabled, 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>()) .def("set_misc_io_analog_output", &IDeviceSettings::setMiscIOAnalogOutput, pybind11::call_guard<pybind11::gil_scoped_release>())
// Performance blast
.def("is_perf_test_enabled", &IDeviceSettings::isPerfTestEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_perf_test_enable", &IDeviceSettings::setPerfTestEnable, pybind11::call_guard<pybind11::gil_scoped_release>())
// gPTP methods
.def("get_gptp_profile", &IDeviceSettings::getGPTPProfile, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_gptp_profile", &IDeviceSettings::setGPTPProfile, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_gptp_role", &IDeviceSettings::getGPTPRole, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_gptp_role", &IDeviceSettings::setGPTPRole, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_gptp_enabled_port", &IDeviceSettings::getGPTPEnabledPort, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_gptp_enabled_port", &IDeviceSettings::setGPTPEnabledPort, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_gptp_clock_syntonization_enabled", &IDeviceSettings::isGPTPClockSyntonizationEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_gptp_clock_syntonization_enabled", &IDeviceSettings::setGPTPClockSyntonizationEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
// Linux operating-system settings (Fire3 family devices)
.def("get_linux_boot_enabled", &IDeviceSettings::getLinuxBootEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_linux_boot_enabled", &IDeviceSettings::setLinuxBootEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_external_wifi_antenna_enabled", &IDeviceSettings::getExternalWifiAntennaEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_external_wifi_antenna_enabled", &IDeviceSettings::setExternalWifiAntennaEnabled, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_linux_configuration_port", &IDeviceSettings::getLinuxConfigurationPort, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_linux_configuration_port", &IDeviceSettings::setLinuxConfigurationPort, pybind11::call_guard<pybind11::gil_scoped_release>())
// Status properties // Status properties
.def_readonly("disabled", &IDeviceSettings::disabled) .def_readonly("disabled", &IDeviceSettings::disabled)
.def_readonly("readonly", &IDeviceSettings::readonly); .def_readonly("readonly", &IDeviceSettings::readonly);
+10
View File
@@ -19,6 +19,8 @@ void init_ethernetmessage(pybind11::module_&);
void init_linmessage(pybind11::module_&); void init_linmessage(pybind11::module_&);
void init_tc10statusmessage(pybind11::module_&); void init_tc10statusmessage(pybind11::module_&);
void init_gptpstatusmessage(pybind11::module_&); void init_gptpstatusmessage(pybind11::module_&);
void init_allmacaddressesmessage(pybind11::module_&);
void init_apperrormessage(pybind11::module_&);
void init_mdiomessage(pybind11::module_&); void init_mdiomessage(pybind11::module_&);
void init_spimessage(pybind11::module_&); void init_spimessage(pybind11::module_&);
void init_ethernetstatusmessage(pybind11::module_&); void init_ethernetstatusmessage(pybind11::module_&);
@@ -30,7 +32,10 @@ void init_deviceextension(pybind11::module_&);
void init_chipid(pybind11::module_&); void init_chipid(pybind11::module_&);
void init_versionreport(pybind11::module_&); void init_versionreport(pybind11::module_&);
void init_device(pybind11::module_&); void init_device(pybind11::module_&);
void init_command(pybind11::module_&);
void init_main51message(pybind11::module_&);
void init_messagefilter(pybind11::module_&); void init_messagefilter(pybind11::module_&);
void init_main51messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&); void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&); void init_version(pybind11::module_&);
void init_flexray(pybind11::module_& m); void init_flexray(pybind11::module_& m);
@@ -59,13 +64,18 @@ PYBIND11_MODULE(icsneopy, m) {
init_linmessage(m); init_linmessage(m);
init_tc10statusmessage(m); init_tc10statusmessage(m);
init_gptpstatusmessage(m); init_gptpstatusmessage(m);
init_allmacaddressesmessage(m);
init_apperrormessage(m);
init_mdiomessage(m); init_mdiomessage(m);
init_ethernetstatusmessage(m); init_ethernetstatusmessage(m);
init_macsecconfig(m); init_macsecconfig(m);
init_scriptstatusmessage(m); init_scriptstatusmessage(m);
init_spimessage(m); init_spimessage(m);
init_livedatamessage(m); init_livedatamessage(m);
init_command(m);
init_main51message(m);
init_messagefilter(m); init_messagefilter(m);
init_main51messagefilter(m);
init_messagecallback(m); init_messagecallback(m);
init_diskdriver(m); init_diskdriver(m);
init_diskdetails(m); init_diskdetails(m);
+1 -2
View File
@@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON \ cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
-DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
cmake --build build || exit 1 cmake --build build || exit 1
+1 -2
View File
@@ -3,7 +3,6 @@
mkdir build >nul 2>&1 mkdir build >nul 2>&1
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_UNIT_TESTS=ON ^ cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DLIBICSNEO_BUILD_UNIT_TESTS=ON-DLIBICSNEO_ENABLE_TCP=ON || exit /b 1
-DLIBICSNEO_ENABLE_TCP=ON || exit /b 1
cmake --build build || exit /b 1 cmake --build build || exit /b 1
+32
View File
@@ -21,10 +21,15 @@
#include "icsneo/communication/message/hardwareinfo.h" #include "icsneo/communication/message/hardwareinfo.h"
#include "icsneo/communication/message/tc10statusmessage.h" #include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/gptpstatusmessage.h" #include "icsneo/communication/message/gptpstatusmessage.h"
#include "icsneo/communication/message/allmacaddressesmessage.h"
#include "icsneo/communication/message/apperrormessage.h" #include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/ethernetstatusmessage.h" #include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/message/networkmutexmessage.h" #include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/clientidmessage.h" #include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/communication/message/genericapidatamessage.h"
#include "icsneo/communication/message/genericapistatusmessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
@@ -39,6 +44,7 @@
#include "icsneo/communication/packet/i2cpacket.h" #include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/packet/scriptstatuspacket.h" #include "icsneo/communication/packet/scriptstatuspacket.h"
#include "icsneo/communication/packet/linpacket.h" #include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/iso15765message.h"
#include "icsneo/communication/packet/componentversionpacket.h" #include "icsneo/communication/packet/componentversionpacket.h"
#include "icsneo/communication/packet/supportedfeaturespacket.h" #include "icsneo/communication/packet/supportedfeaturespacket.h"
#include "icsneo/communication/packet/mdiopacket.h" #include "icsneo/communication/packet/mdiopacket.h"
@@ -340,9 +346,21 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::LiveData: case ExtendedCommand::LiveData:
result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report); result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report);
return true; return true;
case ExtendedCommand::ExecuteSPIPortKeyOperation:
result = SPIPortKeyMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::ReadGenericAPIData:
result = GenericAPIDataMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::ReadGenericAPIStatus:
result = GenericAPIStatusMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetTC10Status: case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data); result = TC10StatusMessage::DecodeToMessage(packet->data);
return true; return true;
case ExtendedCommand::GetAllMACAddresses:
result = AllMACAddressesMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetGPTPStatus: { case ExtendedCommand::GetGPTPStatus: {
result = GPTPStatus::DecodeToMessage(packet->data, report); result = GPTPStatus::DecodeToMessage(packet->data, report);
return true; return true;
@@ -355,6 +373,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
); );
protoapi::Id protoId = protoapi::getProtoId(responseBody.data(), responseBody.size()); protoapi::Id protoId = protoapi::getProtoId(responseBody.data(), responseBody.size());
switch(protoId) { switch(protoId) {
case protoapi::Id::MfgConfig:
result = MfgConfigMessage::DecodeToMessage(responseBody);
return true;
case protoapi::Id::NetworkMutex: case protoapi::Id::NetworkMutex:
result = NetworkMutexMessage::DecodeToMessage(responseBody); result = NetworkMutexMessage::DecodeToMessage(responseBody);
return true; return true;
@@ -459,6 +480,14 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true; return true;
} }
case Command::J2534Command: {
result = J2534CommandMessage::decodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
default: default:
auto msg = std::make_shared<Main51Message>(); auto msg = std::make_shared<Main51Message>();
msg->command = Command(packet->data[0]); msg->command = Command(packet->data[0]);
@@ -559,6 +588,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
break; break;
} }
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
} }
// For the moment other types of messages will automatically be decoded as raw messages // For the moment other types of messages will automatically be decoded as raw messages
+3 -1
View File
@@ -234,7 +234,9 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
result = packetizer.packetWrap(result, false); result = packetizer.packetWrap(result, false);
return true; return true;
} }
break; default:
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Message
} }
// Early returns may mean we don't reach this far, check the type you're concerned with // Early returns may mean we don't reach this far, check the type you're concerned with
+2
View File
@@ -163,6 +163,8 @@ void A2BMessage::setChannelSample(Direction dir, uint8_t channel, size_t frame,
case PCMType::L24: case PCMType::L24:
sampleToSet = sampleToSet << 8; sampleToSet = sampleToSet << 8;
break; break;
case PCMType::L32:
break;
} }
if(channelSize16) { if(channelSize16) {
@@ -0,0 +1,51 @@
#include "icsneo/communication/message/allmacaddressesmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/network.h"
#include <cstring>
using namespace icsneo;
#pragma pack(push, 2)
struct ResponseHeader {
ExtendedCommand command;
uint16_t length;
uint16_t count;
};
struct MacAddrEntryPacket {
uint16_t networkId;
uint8_t address[MACAddressLength];
};
#pragma pack(pop)
std::shared_ptr<AllMACAddressesMessage> AllMACAddressesMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::GetAllMACAddresses)
return nullptr;
if(hdr->count > MaxMACAddressCount)
return nullptr;
const size_t required = sizeof(ResponseHeader) + hdr->count * sizeof(MacAddrEntryPacket);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<AllMACAddressesMessage>();
const auto* entries = reinterpret_cast<const MacAddrEntryPacket*>(bytestream.data() + sizeof(ResponseHeader));
for(uint16_t i = 0; i < hdr->count; ++i) {
// The firmware sends CoreMini network IDs — convert to NetID for consistent use in libicsneo
Network::NetID netId = Network::GetNetIDFromCoreMiniNetwork(static_cast<Network::CoreMini>(entries[i].networkId));
auto addr = entries[i].address;
MACAddress arrAddr;
std::copy(addr, addr + MACAddressLength, arrAddr.begin());
msg->addresses.emplace(std::make_pair(netId, arrAddr));
}
return msg;
}
@@ -37,7 +37,7 @@ struct Packet {
}; };
#pragma pack(pop) #pragma pack(pop)
std::shared_ptr<Message> EthernetStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<RawMessage> EthernetStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) { if(bytestream.size() < sizeof(Packet)) {
return nullptr; return nullptr;
} }
@@ -76,5 +76,5 @@ std::shared_ptr<Message> EthernetStatusMessage::DecodeToMessage(const std::vecto
break; break;
default: return nullptr; default: return nullptr;
} }
return std::make_shared<EthernetStatusMessage>(packet->network, packet->state, speed, packet->duplex, mode); return std::make_shared<EthernetStatusMessage>(packet->network, packet->state != 0, speed, packet->duplex != 0, mode);
} }
+1 -1
View File
@@ -35,7 +35,7 @@ bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t ph
bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message) bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message)
{ {
if(message != nullptr) if(message)
{ {
messages.push_back(message); messages.push_back(message);
return true; return true;
@@ -0,0 +1,28 @@
#include "icsneo/communication/message/genericapidatamessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
std::shared_ptr<GenericAPIDataMessage> GenericAPIDataMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ExtendedResponseMessage::ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::ReadGenericAPIData)
return nullptr;
const size_t required = sizeof(ExtendedResponseMessage::ResponseHeader) + sizeof(GenericAPIDataHeader);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<GenericAPIDataMessage>();
const auto* packet = reinterpret_cast<const GenericAPIDataPacket*>(bytestream.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
msg->functionId = packet->header.functionId;
msg->buffer.resize(packet->header.bufferLength);
std::copy(packet->buffer, packet->buffer + packet->header.bufferLength, msg->buffer.data());
return msg;
}
@@ -0,0 +1,29 @@
#include "icsneo/communication/message/genericapistatusmessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
std::shared_ptr<GenericAPIStatusMessage> GenericAPIStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ExtendedResponseMessage::ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::ReadGenericAPIStatus)
return nullptr;
const size_t required = sizeof(ExtendedResponseMessage::ResponseHeader) + sizeof(GenericAPIStatusResponsePacket);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<GenericAPIStatusMessage>();
const auto* packet = reinterpret_cast<const GenericAPIStatusResponsePacket*>(bytestream.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
msg->functionId = packet->functionId;
msg->finishedProcessing = static_cast<bool>(packet->finishedProcessing);
msg->functionError = packet->functionError;
msg->callbackError = packet->callbackError;
return msg;
}
+337
View File
@@ -0,0 +1,337 @@
#include "icsneo/communication/message/iso15765message.h"
#include <cstring>
using namespace icsneo;
std::shared_ptr<J2534CommandMessage> J2534CommandMessage::decodeToMessage(const std::vector<uint8_t>& data) {
if(data.size() < 2)
return nullptr;
auto msg = std::make_shared<J2534CommandMessage>((J2534Command)data[1]);
if(data.size() > 2)
msg->setArgumentData(std::vector<uint8_t>(data.begin() + 2, data.end()));
return msg;
}
uint16_t J2534CommandMessage::read16LE(size_t o) const {
return (uint16_t)((uint16_t)argumentData[o] | ((uint16_t)argumentData[o + 1] << 8));
}
void J2534CommandMessage::write16LE(size_t o, uint16_t v) {
argumentData[o] = (uint8_t)(v & 0xFF);
argumentData[o + 1] = (uint8_t)((v >> 8) & 0xFF);
}
uint16_t J2534CommandMessage::read16BE(size_t o) const {
return (uint16_t)(((uint16_t)argumentData[o] << 8) | argumentData[o + 1]);
}
void J2534CommandMessage::write16BE(size_t o, uint16_t v) {
argumentData[o] = (uint8_t)((v >> 8) & 0xFF);
argumentData[o + 1] = (uint8_t)(v & 0xFF);
}
void J2534CommandMessage::writeBits16LE(size_t o, unsigned bitPos, unsigned bitCount, uint32_t value) {
const uint16_t mask = (uint16_t)(((1u << bitCount) - 1u) << bitPos);
uint16_t word = read16LE(o);
word = (uint16_t)((word & ~mask) | (((value << bitPos) & mask)));
write16LE(o, word);
}
uint32_t J2534CommandMessage::read32LE(size_t o) const {
return (uint32_t)argumentData[o]
| ((uint32_t)argumentData[o + 1] << 8)
| ((uint32_t)argumentData[o + 2] << 16)
| ((uint32_t)argumentData[o + 3] << 24);
}
void J2534CommandMessage::write32LE(size_t o, uint32_t v) {
argumentData[o] = (uint8_t)(v & 0xFF);
argumentData[o + 1] = (uint8_t)((v >> 8) & 0xFF);
argumentData[o + 2] = (uint8_t)((v >> 16) & 0xFF);
argumentData[o + 3] = (uint8_t)((v >> 24) & 0xFF);
}
uint32_t J2534CommandMessage::read32BE(size_t o) const {
return ((uint32_t)argumentData[o] << 24) | ((uint32_t)argumentData[o + 1] << 16)
| ((uint32_t)argumentData[o + 2] << 8) | (uint32_t)argumentData[o + 3];
}
void J2534CommandMessage::write32BE(size_t o, uint32_t v) {
argumentData[o] = (uint8_t)((v >> 24) & 0xFF);
argumentData[o + 1] = (uint8_t)((v >> 16) & 0xFF);
argumentData[o + 2] = (uint8_t)((v >> 8) & 0xFF);
argumentData[o + 3] = (uint8_t)(v & 0xFF);
}
J2534_RxCanFilter J2534SetupCanRxFilteringMessage::getRxCanFilter() const {
constexpr size_t filterSize = sizeof(J2534_RxCanFilter::fb);
J2534_RxCanFilter filter = {};
if(argumentData.size() >= (10 + filterSize))
{
filter.idx = (argumentData[2] << 8) | argumentData[3];
filter.enabled = (argumentData[4] << 8) | argumentData[5];
filter.filterCount = (argumentData[6] << 8) | argumentData[7];
filter.fb = *((MessageFilterBytes*)(argumentData.data() + 8));
filter.networkId = (argumentData[8 + filterSize] << 8) | argumentData[9 + filterSize];
}
return filter;
}
void J2534SetupCanRxFilteringMessage::setRxCanFilter(const J2534_RxCanFilter& filter) {
argumentData.resize(10 + sizeof(filter.fb));
argumentData[2] = (filter.idx >> 8) & 0xFF;
argumentData[3] = filter.idx & 0xFF;
argumentData[4] = (filter.enabled >> 8) & 0xFF;
argumentData[5] = filter.enabled & 0xFF;
argumentData[6] = (filter.filterCount >> 8) & 0xFF;
argumentData[7] = filter.filterCount & 0xFF;
*((MessageFilterBytes*)(argumentData.data() + 8)) = filter.fb;
argumentData[8 + sizeof(filter.fb)] = (filter.networkId >> 8) & 0xFF;
argumentData[9 + sizeof(filter.fb)] = filter.networkId & 0xFF;
}
J2534SetupIso15765FlowControlMessage::J2534SetupIso15765FlowControlMessage()
: J2534CommandMessage(J2534Command::SetupIso15765RxFilter) {
argumentData.resize(MessageSize);
// Bytes [0..1] were populated by the base constructor. Everything else starts at zero
// (matches the previous behavior which zeroed the flt region and left the rest of the
// caller-supplied struct as-is; typical callers value-initialized their struct too).
for(size_t i = 2; i < MessageSize; ++i)
argumentData[i] = 0;
}
void J2534SetupIso15765FlowControlMessage::rebuildFilterBytes(void) {
// Zero the 28-byte flt region.
for(size_t i = 0; i < FltSize; ++i)
argumentData[FltOffset + i] = 0;
const uint32_t id = read32LE(IdOffset);
const uint32_t idMask = read32LE(IdMaskOffset);
const bool is29Bit = getFlagBit(FlagId29BitEnable);
const bool extAddr = getFlagBit(FlagExtAddressEnable);
const uint8_t extAddrByte = argumentData[ExtAddrOffset];
// CoreMiniMessageFilterBytes has an interleaved layout:
// uiFilterMask0 at flt+0, uiFilterID0 at flt+2
// uiFilterMask1 at flt+4, uiFilterID1 at flt+6
// uiFilterMask2 at flt+8, uiFilterID2 at flt+10
// datalink.uiFilterMask3 at flt+12, datalink.uiFilterID3 at flt+14
//
// CoreMiniMsgBitsCAN bit layout within each 16-bit unit:
// unit0: IDE(bit0), SRR(bit1), SID(bits2-12), NETWORKINDEX(bits13-15)
// unit1: EID(bits0-11), TXMSG(bit12), ...
// unit2: DLC(bits0-3), ..., RTR(bit9), EID2(bits10-15)
const size_t MaskUnit0 = FltOffset + 0;
const size_t MaskUnit1 = FltOffset + 4;
const size_t MaskUnit2 = FltOffset + 8;
const size_t ValueUnit0 = FltOffset + 2;
const size_t ValueUnit1 = FltOffset + 6;
const size_t ValueUnit2 = FltOffset + 10;
// filter arbid: pMask->IDE = 1
writeBits16LE(MaskUnit0, /*bit*/0, /*width*/1, 1);
if(is29Bit) {
// pValue->IDE = 1; pValue->SID = (id >> 18) & 0x7FF
writeBits16LE(ValueUnit0, 0, 1, 1);
writeBits16LE(ValueUnit0, 2, 11, (id >> 18) & 0x7FF);
// pValue->EID = (id >> 6) & 0xFFF
writeBits16LE(ValueUnit1, 0, 12, (id >> 6) & 0xFFF);
// pValue->EID2 = id & 0x3F
writeBits16LE(ValueUnit2, 10, 6, id & 0x3F);
// pMask->SID = (id_mask >> 18) & 0x7FF
writeBits16LE(MaskUnit0, 2, 11, (idMask >> 18) & 0x7FF);
// pMask->EID = (id_mask >> 6) & 0xFFF (overlaps pValue->{IDE,SID} storage)
writeBits16LE(MaskUnit1, 0, 12, (idMask >> 6) & 0xFFF);
// pMask->EID2 = id_mask & 0x3F (overlaps pValue->EID storage)
writeBits16LE(MaskUnit2, 10, 6, idMask & 0x3F);
} else {
// pValue->IDE = 0 (already zero); pValue->SID = id
writeBits16LE(ValueUnit0, 2, 11, id & 0x7FF);
// pMask->SID = id_mask
writeBits16LE(MaskUnit0, 2, 11, idMask & 0x7FF);
}
// Extended-address filter: writes into the datalink.uiFilterID3 / uiFilterMask3 bytes.
// uiFilterMask3 = flt[12..13] = wire[37..38]
// uiFilterID3 = flt[14..15] = wire[39..40]
if(extAddr) {
const size_t kValueBytes = FltOffset + 14; // uiFilterID3
const size_t kMaskBytes = FltOffset + 12; // uiFilterMask3
argumentData[kValueBytes + 0] = extAddrByte;
argumentData[kMaskBytes + 0] = 0xFF;
argumentData[kValueBytes + 1] = 0;
argumentData[kMaskBytes + 1] = 0;
}
}
uint16_t J2534SetupIso15765FlowControlMessage::getIdx(void) const { return read16LE(IdxOffset); }
void J2534SetupIso15765FlowControlMessage::setIdx(uint16_t idx) { write16LE(IdxOffset, idx); }
uint16_t J2534SetupIso15765FlowControlMessage::getCoreMiniId(void) const { return read16LE(CoreMiniOffset); }
void J2534SetupIso15765FlowControlMessage::setCoreMiniId(uint16_t coreMiniId) { write16LE(CoreMiniOffset, coreMiniId); }
uint8_t J2534SetupIso15765FlowControlMessage::getPadding(void) const { return argumentData[PaddingOffset]; }
void J2534SetupIso15765FlowControlMessage::setPadding(uint8_t padding) { argumentData[PaddingOffset] = padding; }
uint32_t J2534SetupIso15765FlowControlMessage::getId(void) const { return read32LE(IdOffset); }
void J2534SetupIso15765FlowControlMessage::setId(uint32_t id) { write32LE(IdOffset, id); rebuildFilterBytes(); }
uint32_t J2534SetupIso15765FlowControlMessage::getIdMask(void) const { return read32LE(IdMaskOffset); }
void J2534SetupIso15765FlowControlMessage::setIdMask(uint32_t idMask) { write32LE(IdMaskOffset, idMask); rebuildFilterBytes(); }
uint32_t J2534SetupIso15765FlowControlMessage::getFcId(void) const { return read32LE(FcIdOffset); }
void J2534SetupIso15765FlowControlMessage::setFcId(uint32_t fcId) { write32LE(FcIdOffset, fcId); }
uint8_t J2534SetupIso15765FlowControlMessage::getFlowControlExtendedAddress(void) const { return argumentData[FcExtAddrOffset]; }
void J2534SetupIso15765FlowControlMessage::setFlowControlExtendedAddress(uint8_t addr) { argumentData[FcExtAddrOffset] = addr; }
uint8_t J2534SetupIso15765FlowControlMessage::getExtendedAddress(void) const { return argumentData[ExtAddrOffset]; }
void J2534SetupIso15765FlowControlMessage::setExtendedAddress(uint8_t addr) { argumentData[ExtAddrOffset] = addr; rebuildFilterBytes(); }
uint8_t J2534SetupIso15765FlowControlMessage::getBlockSize(void) const { return argumentData[BlockSizeOffset]; }
void J2534SetupIso15765FlowControlMessage::setBlockSize(uint8_t blockSize) { argumentData[BlockSizeOffset] = blockSize; }
uint8_t J2534SetupIso15765FlowControlMessage::getStMin(void) const { return argumentData[StMinOffset]; }
void J2534SetupIso15765FlowControlMessage::setStMin(uint8_t stMin) { argumentData[StMinOffset] = stMin; }
uint16_t J2534SetupIso15765FlowControlMessage::getCfTimeout(void) const { return read16LE(CfTimeoutOffset); }
void J2534SetupIso15765FlowControlMessage::setCfTimeout(uint16_t cfTimeout) { write16LE(CfTimeoutOffset, cfTimeout); }
uint32_t J2534SetupIso15765FlowControlMessage::getFlags(void) const { return read32LE(FlagsOffset); }
void J2534SetupIso15765FlowControlMessage::setFlags(uint32_t flags) { write32LE(FlagsOffset, flags); rebuildFilterBytes(); }
bool J2534SetupIso15765FlowControlMessage::getEnable(void) const { return getFlagBit(FlagEnable); }
void J2534SetupIso15765FlowControlMessage::setEnable(bool enable) { setFlagBit(FlagEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getIs29BitEnabled(void) const { return getFlagBit(FlagId29BitEnable); }
void J2534SetupIso15765FlowControlMessage::setIs29BitEnabled(bool enable) { setFlagBit(FlagId29BitEnable, enable); rebuildFilterBytes(); }
bool J2534SetupIso15765FlowControlMessage::getIsFc29BitEnabled(void) const { return getFlagBit(FlagFcId29BitEnable); }
void J2534SetupIso15765FlowControlMessage::setIsFc29BitEnabled(bool enable) { setFlagBit(FlagFcId29BitEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getExtAddressEnabled(void) const { return getFlagBit(FlagExtAddressEnable); }
void J2534SetupIso15765FlowControlMessage::setExtAddressEnabled(bool enable) { setFlagBit(FlagExtAddressEnable, enable); rebuildFilterBytes(); }
bool J2534SetupIso15765FlowControlMessage::getFcExtAddressEnabled(void) const { return getFlagBit(FlagFcExtAddressEnable); }
void J2534SetupIso15765FlowControlMessage::setFcExtAddressEnabled(bool enable) { setFlagBit(FlagFcExtAddressEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getFlowControlTransmissionEnabled(void) const { return getFlagBit(FlagEnableFlowControlTransmit); }
void J2534SetupIso15765FlowControlMessage::setFlowControlTransmissionEnabled(bool enable) { setFlagBit(FlagEnableFlowControlTransmit, enable); }
bool J2534SetupIso15765FlowControlMessage::getPaddingEnabled(void) const { return getFlagBit(FlagPaddingEnable); }
void J2534SetupIso15765FlowControlMessage::setPaddingEnabled(bool enable) { setFlagBit(FlagPaddingEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getIsCanFd(void) const { return getFlagBit(FlagIsCanFd); }
void J2534SetupIso15765FlowControlMessage::setIsCanFd(bool enable) { setFlagBit(FlagIsCanFd, enable); }
bool J2534SetupIso15765FlowControlMessage::getIsBrsEnabled(void) const { return getFlagBit(FlagIsBrsEnabled); }
void J2534SetupIso15765FlowControlMessage::setIsBrsEnabled(bool enable) { setFlagBit(FlagIsBrsEnabled, enable); }
void J2534SetupIso15765FlowControlMessage::setFlagBit(uint32_t mask, bool enable) {
uint32_t f = read32LE(FlagsOffset);
if(enable) f |= mask;
else f &= ~mask;
write32LE(FlagsOffset, f);
}
bool J2534SetupIso15765FlowControlMessage::getFlagBit(uint32_t mask) const {
return (read32LE(FlagsOffset) & mask) != 0;
}
uint16_t Iso15765TxSetupMessage::getIdx(void) const { return read16LE(SetupIdxOffset); }
void Iso15765TxSetupMessage::setIdx(uint16_t idx) { write16LE(SetupIdxOffset, idx); }
uint16_t Iso15765TxSetupMessage::getCoreMiniId(void) const { return read16LE(SetupCoreMiniOffset); }
void Iso15765TxSetupMessage::setCoreMiniId(uint16_t coreMiniId) { write16LE(SetupCoreMiniOffset, coreMiniId); }
uint32_t Iso15765TxSetupMessage::getMessageLength(void) const { return read32LE(SetupMsgLenOffset); }
void Iso15765TxSetupMessage::setMessageLength(uint32_t messageLength) { write32LE(SetupMsgLenOffset, messageLength); }
uint8_t Iso15765TxSetupMessage::getPadding(void) const { return argumentData[SetupPaddingOffset]; }
void Iso15765TxSetupMessage::setPadding(uint8_t padding) { argumentData[SetupPaddingOffset] = padding; }
uint8_t Iso15765TxSetupMessage::getTxDl(void) const { return argumentData[SetupTxDlOffset]; }
void Iso15765TxSetupMessage::setTxDl(uint8_t txDl) { argumentData[SetupTxDlOffset] = txDl; }
uint32_t Iso15765TxSetupMessage::getId(void) const { return read32LE(SetupIdOffset); }
void Iso15765TxSetupMessage::setId(uint32_t id) { write32LE(SetupIdOffset, id); }
uint32_t Iso15765TxSetupMessage::getFcId(void) const { return read32LE(SetupFcIdOffset); }
void Iso15765TxSetupMessage::setFcId(uint32_t fcId) { write32LE(SetupFcIdOffset, fcId); }
uint32_t Iso15765TxSetupMessage::getFcIdMask(void) const { return read32LE(SetupFcIdMaskOffset); }
void Iso15765TxSetupMessage::setFcIdMask(uint32_t fcIdMask) { write32LE(SetupFcIdMaskOffset, fcIdMask); }
uint8_t Iso15765TxSetupMessage::getFlowControlExtendedAddress(void) const { return argumentData[SetupFcExtAddrOffset]; }
void Iso15765TxSetupMessage::setFlowControlExtendedAddress(uint8_t addr) { argumentData[SetupFcExtAddrOffset] = addr; }
uint8_t Iso15765TxSetupMessage::getExtendedAddress(void) const { return argumentData[SetupExtAddrOffset]; }
void Iso15765TxSetupMessage::setExtendedAddress(uint8_t addr) { argumentData[SetupExtAddrOffset] = addr; }
uint16_t Iso15765TxSetupMessage::getFsTimeout(void) const { return read16LE(SetupFsTimeoutOffset); }
void Iso15765TxSetupMessage::setFsTimeout(uint16_t timeout) { write16LE(SetupFsTimeoutOffset, timeout); }
uint16_t Iso15765TxSetupMessage::getFsWait(void) const { return read16LE(SetupFsWaitOffset); }
void Iso15765TxSetupMessage::setFsWait(uint16_t wait) { write16LE(SetupFsWaitOffset, wait); }
uint32_t Iso15765TxSetupMessage::getFlags(void) const { return read32LE(SetupFlagsOffset); }
void Iso15765TxSetupMessage::setFlags(uint32_t flags) { write32LE(SetupFlagsOffset, flags); }
uint8_t Iso15765TxSetupMessage::getStMin(void) const { return argumentData[SetupStMinOffset]; }
void Iso15765TxSetupMessage::setStMin(uint8_t stMin) { argumentData[SetupStMinOffset] = stMin; }
uint8_t Iso15765TxSetupMessage::getBlockSize(void) const { return argumentData[SetupBlockSizeOffset]; }
void Iso15765TxSetupMessage::setBlockSize(uint8_t blockSize) { argumentData[SetupBlockSizeOffset] = blockSize; }
bool Iso15765TxSetupMessage::getIs29BitEnabled(void) const { return getFlagBit(FlagId29BitEnable); }
void Iso15765TxSetupMessage::setIs29BitEnabled(bool enable) { setFlagBit(FlagId29BitEnable, enable); }
bool Iso15765TxSetupMessage::getIsFc29BitEnabled(void) const { return getFlagBit(FlagFcId29BitEnable); }
void Iso15765TxSetupMessage::setIsFc29BitEnabled(bool enable) { setFlagBit(FlagFcId29BitEnable, enable); }
bool Iso15765TxSetupMessage::getExtAddressEnabled(void) const { return getFlagBit(FlagExtAddressEnable); }
void Iso15765TxSetupMessage::setExtAddressEnabled(bool enable) { setFlagBit(FlagExtAddressEnable, enable); }
bool Iso15765TxSetupMessage::getFcExtAddressEnabled(void) const { return getFlagBit(FlagFcExtAddressEnable); }
void Iso15765TxSetupMessage::setFcExtAddressEnabled(bool enable) { setFlagBit(FlagFcExtAddressEnable, enable); }
bool Iso15765TxSetupMessage::getOverrideStMin(void) const { return getFlagBit(FlagOverrideStMin); }
void Iso15765TxSetupMessage::setOverrideStMin(bool enable) { setFlagBit(FlagOverrideStMin, enable); }
bool Iso15765TxSetupMessage::getOverrideBlockSize(void) const { return getFlagBit(FlagOverrideBlockSize); }
void Iso15765TxSetupMessage::setOverrideBlockSize(bool enable) { setFlagBit(FlagOverrideBlockSize, enable); }
bool Iso15765TxSetupMessage::getPaddingEnabled(void) const { return getFlagBit(FlagPaddingEnable); }
void Iso15765TxSetupMessage::setPaddingEnabled(bool enable) { setFlagBit(FlagPaddingEnable, enable); }
bool Iso15765TxSetupMessage::getIsCanFd(void) const { return getFlagBit(FlagIsCanFd); }
void Iso15765TxSetupMessage::setIsCanFd(bool enable) { setFlagBit(FlagIsCanFd, enable); }
bool Iso15765TxSetupMessage::getIsBrsEnabled(void) const { return getFlagBit(FlagIsBrsEnabled); }
void Iso15765TxSetupMessage::setIsBrsEnabled(bool enable) { setFlagBit(FlagIsBrsEnabled, enable); }
bool Iso15765TxSetupMessage::getFlagBit(uint32_t mask) const {
return (getFlags() & mask) != 0;
}
void Iso15765TxSetupMessage::setFlagBit(uint32_t mask, bool enable) {
uint32_t f = getFlags();
if(enable) f |= mask;
else f &= ~mask;
setFlags(f);
}
uint16_t Iso15765TxDataMessage::getIdx(void) const { return read16LE(DataIdxOffset); }
void Iso15765TxDataMessage::setIdx(uint16_t idx) { write16LE(DataIdxOffset, idx); }
uint32_t Iso15765TxDataMessage::getOffset(void) const { return read32LE(DataOffsetOffset); }
void Iso15765TxDataMessage::setOffset(uint32_t offset) { write32LE(DataOffsetOffset, offset); }
uint16_t Iso15765TxDataMessage::getLen(void) const { return read16LE(DataLenOffset); }
const uint8_t* Iso15765TxDataMessage::getData(void) const { return argumentData.data() + DataPayloadOffset; }
void Iso15765TxDataMessage::setData(const uint8_t* sourceData, uint16_t len) {
len = std::min(len, (uint16_t)MaxDataLength);
argumentData.resize(DataPayloadOffset + len);
write16LE(DataLenOffset, len);
if(len > 0 && sourceData != nullptr)
std::copy(sourceData, sourceData + len, argumentData.begin() + DataPayloadOffset);
}
@@ -0,0 +1,77 @@
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/icspb.h"
#include <algorithm>
using namespace icsneo;
static MfgConfigMessage::VersionNumber versionFromProto(const settings::common::v1::VersionNumber& version) {
MfgConfigMessage::VersionNumber decoded;
decoded.major = version.major();
decoded.minor = version.minor();
if(version.has_release())
decoded.release = version.release();
if(version.has_build())
decoded.build = version.build();
return decoded;
}
std::shared_ptr<MfgConfigMessage> MfgConfigMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
MfgConfigMessage decoded;
settings::manufacturing::v1::MfgConfig msg;
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
return nullptr;
}
if(msg.has_serial_number()) {
decoded.serialNumber = msg.serial_number();
}
if(msg.has_manufacture_date()) {
const auto& date = msg.manufacture_date();
decoded.manufactureDate = MfgDate{date.manufacture_day(), date.manufacture_month(), date.manufacture_year()};
}
if(msg.has_hardware_rev()) {
decoded.hardwareRev = versionFromProto(msg.hardware_rev());
}
if(msg.has_product_id()) {
decoded.productId = static_cast<uint8_t>(msg.product_id());
}
if(msg.has_bootloader_rev()) {
decoded.bootloaderRev = versionFromProto(msg.bootloader_rev());
}
if(msg.has_usb_descriptor()) {
decoded.usbDescriptor = msg.usb_descriptor();
}
for(const auto& mac : msg.mac_addresses()) {
const auto& bytes = mac.mac_addr();
if(bytes.size() < MACAddressLength)
continue;
MACAddress address{};
std::copy_n(bytes.begin(), MACAddressLength, address.begin());
decoded.macAddresses.push_back(address);
}
if(msg.has_pcb_serial()) {
decoded.pcbSerial = msg.pcb_serial().pcb_serial();
}
if(msg.has_chip_id()) {
decoded.chipId = static_cast<ChipID>(msg.chip_id());
}
if(msg.has_imei()) {
decoded.imei = msg.imei();
}
if(msg.has_parent_product_id()) {
decoded.parentProductId = static_cast<uint8_t>(msg.parent_product_id());
}
if(msg.has_software_version_lock()) {
decoded.softwareVersionLock = versionFromProto(msg.software_version_lock());
}
return std::make_shared<MfgConfigMessage>(decoded);
}
std::vector<uint8_t> MfgConfigMessage::EncodeArgumentsForGet() {
settings::manufacturing::v1::MfgConfig msg;
msg.Clear();
return protoapi::getPayload(protoapi::Command::GET, msg);
}
@@ -0,0 +1,27 @@
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/communication/network.h"
using namespace icsneo;
std::shared_ptr<SPIPortKeyMessage> SPIPortKeyMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ExtendedResponseMessage::ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::ExecuteSPIPortKeyOperation)
return nullptr;
const size_t required = sizeof(ExtendedResponseMessage::ResponseHeader) + sizeof(SPIPortKeyPacket);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<SPIPortKeyMessage>();
const auto* packet = reinterpret_cast<const SPIPortKeyPacket*>(bytestream.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
msg->isKeyLoaded = packet->isKeyLoaded;
return msg;
}
@@ -137,6 +137,7 @@ static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, c
linpacket->CoreMiniBitsLIN.TXResponder = 1; linpacket->CoreMiniBitsLIN.TXResponder = 1;
break; break;
case LINMessage::Type::LIN_BREAK_ONLY: case LINMessage::Type::LIN_BREAK_ONLY:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
linpacket->CoreMiniBitsLIN.BreakOnly = 1; linpacket->CoreMiniBitsLIN.BreakOnly = 1;
break; break;
default: default:
@@ -142,6 +142,8 @@ void MultiChannelCommunication::hidReadTask() {
dispatchMessage(msg); dispatchMessage(msg);
break; break;
} }
default:
break;
} }
if(currentQueue == nullptr) { if(currentQueue == nullptr) {
+17 -5
View File
@@ -72,18 +72,30 @@ std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<ui
static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce), static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce), static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered), static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered),
static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly) static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly),
static_cast<bool>(packet->CoreMiniBitsLIN.WakeupRequest)
}; };
if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder) // Wake type only for a wake-only pulse. A UART/LIN break or a complete
// frame may also carry WakeupRequest; those keep their existing type.
const bool wakeupPulse = msg->statusFlags.WakeupRequest &&
packet->CoreMiniBitsLIN.len == 0 &&
packet->CoreMiniBitsLIN.ID == 0 &&
!msg->statusFlags.BreakOnly &&
!msg->errFlags.ErrRxBreakOnly &&
!msg->errFlags.ErrRxBreakSyncOnly;
if(wakeupPulse)
msg->linMsgType = LINMessage::Type::LIN_WAKEUP_REQUEST;
else if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder)
msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG; msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG;
else if(msg->statusFlags.BreakOnly) else if(msg->statusFlags.BreakOnly)
msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY; msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY;
if( msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly || if( !wakeupPulse &&
(msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly ||
msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero || msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero ||
msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 || msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 ||
msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync || msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync ||
msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch || msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch ||
msg->errFlags.ErrFrameResponderData ) msg->errFlags.ErrFrameResponderData) )
{ msg->linMsgType = LINMessage::Type::LIN_ERROR; } { msg->linMsgType = LINMessage::Type::LIN_ERROR; }
msg->timestamp = packet->timestamp; msg->timestamp = packet->timestamp;
@@ -103,7 +115,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
} }
case LINMessage::Type::LIN_BREAK_ONLY: case LINMessage::Type::LIN_BREAK_ONLY:
{ {
size |= 0x20u; size |= 0x80u | 0x20u;
break; break;
} }
case LINMessage::Type::NOT_SET: case LINMessage::Type::NOT_SET:
+1 -1
View File
@@ -80,7 +80,7 @@ bool Packetizer::input(RingBuffer& bytes) {
* end of the payload. The short packet length, for reference, only encompasses the length of the actual * end of the payload. The short packet length, for reference, only encompasses the length of the actual
* payload, and not the header or checksum. * payload, and not the header or checksum.
*/ */
if(packetLength < 6 || packetLength > 4000) { if(packetLength < 6 || packetLength > std::numeric_limits<uint16_t>::max()) {
bytes.pop_front(); bytes.pop_front();
EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error); EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
state = ReadState::SearchForHeader; state = ReadState::SearchForHeader;
+1
View File
@@ -230,6 +230,7 @@ MACsecConfig::MACsecConfig(const DeviceType& deviceType) : type(deviceType) {
case icsneo::DeviceType::Enum::RADMoon2: case icsneo::DeviceType::Enum::RADMoon2:
case icsneo::DeviceType::Enum::RADMoon3: case icsneo::DeviceType::Enum::RADMoon3:
case icsneo::DeviceType::Enum::RADEpsilon: case icsneo::DeviceType::Enum::RADEpsilon:
case icsneo::DeviceType::Enum::RADGigastar2:
maxSecY = 2; maxSecY = 2;
maxRule = 2; maxRule = 2;
maxSa = 4; maxSa = 4;
+400 -143
View File
@@ -8,6 +8,7 @@
#include "icsneo/disk/fat.h" #include "icsneo/disk/fat.h"
#include "icsneo/communication/message/filter/extendedresponsefilter.h" #include "icsneo/communication/message/filter/extendedresponsefilter.h"
#include "icsneo/communication/message/networkmutexmessage.h" #include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/message/transmitmessage.h" #include "icsneo/communication/message/transmitmessage.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@@ -92,10 +93,6 @@ Device::~Device() {
disableMessagePolling(); disableMessagePolling();
if(isOpen()) if(isOpen())
close(); close();
if(heartbeatThread.joinable()) {
stopHeartbeatThread = true;
heartbeatThread.join();
}
} }
uint16_t Device::getTimestampResolution() const { uint16_t Device::getTimestampResolution() const {
@@ -242,12 +239,12 @@ std::vector<VersionReport> Device::getChipVersions(bool refreshComponents) {
auto& version = chipVersions.back(); auto& version = chipVersions.back();
auto disectedVersion = disectVersion(component.dotVersion); auto disectedVersion = disectVersion(component.dotVersion);
version.id = chipInfo.id; version.id = chipInfo.id;
version.name = chipInfo.name; version.name = chipInfo.name;
version.major = disectedVersion[0]; version.major = disectedVersion[0];
version.minor = disectedVersion[1]; version.minor = disectedVersion[1];
version.maintenance = disectedVersion[2]; version.maintenance = disectedVersion[2];
version.build = disectedVersion[3]; version.build = disectedVersion[3];
} }
} }
} }
@@ -267,12 +264,12 @@ std::vector<VersionReport> Device::getChipVersions(bool refreshComponents) {
chipVersions.emplace_back(); chipVersions.emplace_back();
auto& version = chipVersions.back(); auto& version = chipVersions.back();
version.id = chipInfo.id; version.id = chipInfo.id;
version.name = chipInfo.name; version.name = chipInfo.name;
version.major = appVer->major; version.major = appVer->major;
version.minor = appVer->minor; version.minor = appVer->minor;
version.maintenance = 0; version.maintenance = 0;
version.build = 0; version.build = 0;
} }
} }
return chipVersions; return chipVersions;
@@ -288,6 +285,8 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
return false; return false;
} }
startHeartbeat();
APIEvent::Type attemptErr = attemptToBeginCommunication(); APIEvent::Type attemptErr = attemptToBeginCommunication();
if(attemptErr != APIEvent::Type::NoErrorFound) { if(attemptErr != APIEvent::Type::NoErrorFound) {
// We could not communicate with the device, let's see if an extension can // We could not communicate with the device, let's see if an extension can
@@ -334,79 +333,6 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread(); EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread();
} }
MessageFilter filter;
filter.includeInternalInAny = true;
internalHandlerCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [this](std::shared_ptr<Message> message) {
handleInternalMessage(message);
}));
// Clear the previous heartbeat thread, in case open() was called on this instance more than once
if(heartbeatThread.joinable())
heartbeatThread.join();
stopHeartbeatThread = false;
heartbeatThread = std::thread([this]() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
MessageFilter filter;
filter.includeInternalInAny = true;
std::condition_variable heartbeatCV;
std::mutex receivedMessageMutex;
bool receivedMessage = false;
auto messageReceivedCallbackID = com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message>) {
{
std::scoped_lock<std::mutex> lk(receivedMessageMutex);
receivedMessage = true;
}
heartbeatCV.notify_all();
}));
// Give the device time to get situated
auto i = 150;
while(!stopHeartbeatThread && i != 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
i--;
}
while(!stopHeartbeatThread) {
std::unique_lock<std::mutex> recvLk(receivedMessageMutex);
// Wait for 110ms for a possible heartbeat
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(110), [&]() { return receivedMessage; })) {
receivedMessage = false;
} else if(!stopHeartbeatThread) { // Add this condition here in case the thread was stopped while waiting for the last message
// Some communication, such as the bootloader and extractor interfaces, must
// redirect the input stream from the device as it will no longer be in the
// packet format we expect here. As a result, status updates will not reach
// us here and suppressDisconnects() must be used. We don't want to request
// a status and then redirect the stream, as we'll then be polluting an
// otherwise quiet stream. This lock makes sure suppressDisconnects() will
// block until we've either gotten our status update or disconnected from
// the device.
std::unique_lock<std::mutex> lk(heartbeatMutex);
if(heartbeatSuppressed()) continue;
// No heartbeat received, request a status
com->sendCommand(Command::RequestStatusUpdate);
// Check if we got a message, and if not, if settings are being applied
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(3500), [&](){ return receivedMessage; })) {
receivedMessage = false;
} else {
if(!stopHeartbeatThread) {
close();
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}
break;
}
}
}
com->removeMessageCallback(messageReceivedCallbackID);
});
if(supportsLiveData()) if(supportsLiveData())
clearAllLiveData(); clearAllLiveData();
@@ -503,7 +429,7 @@ bool Device::close() {
return false; return false;
} }
stopHeartbeatThread = true; stopHeartbeat();
if (isMessagePollingEnabled()) { if (isMessagePollingEnabled()) {
disableMessagePolling(); disableMessagePolling();
@@ -534,31 +460,15 @@ bool Device::goOnline() {
if(!enableNetworkCommunication(true, onlineTimeoutMs)) if(!enableNetworkCommunication(true, onlineTimeoutMs))
return false; return false;
auto startTime = std::chrono::system_clock::now();
ledState = LEDState::Online; ledState = LEDState::Online;
updateLEDState(); updateLEDState();
std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::Reset_Status); // (re)start the keeponline
filter->includeInternalInAny = true; keeponline = std::make_unique<Periodic>([this] {
static std::vector<uint8_t> timeoutBytes = std::vector<uint8_t>((uint8_t*)&onlineTimeoutMs, (uint8_t*)&onlineTimeoutMs + sizeof(onlineTimeoutMs));
// Wait until communication is enabled or 5 seconds, whichever comes first return com->sendCommand(Command::KeepAlive, timeoutBytes);
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) { }, std::chrono::milliseconds(onlineTimeoutMs / 4));
if(latestResetStatus && latestResetStatus->comEnabled)
break;
bool failOut = false;
com->waitForMessageSync([this, &failOut]() {
if(!com->sendCommand(Command::RequestStatusUpdate)) {
failOut = true;
return false;
}
return true;
}, filter, std::chrono::milliseconds(100));
if(failOut)
return false;
}
if(supportsNetworkMutex) { if(supportsNetworkMutex) {
assignedClientId = com->getClientIDSync(); assignedClientId = com->getClientIDSync();
@@ -575,41 +485,46 @@ bool Device::goOnline() {
case NetworkMutexEvent::Acquired: case NetworkMutexEvent::Acquired:
lockedNetworks.emplace(*netMutexMsg->networks.begin()); lockedNetworks.emplace(*netMutexMsg->networks.begin());
break; break;
case NetworkMutexEvent::Expired:
case NetworkMutexEvent::Preempted:
case NetworkMutexEvent::Released: { case NetworkMutexEvent::Released: {
auto it = lockedNetworks.find(*netMutexMsg->networks.begin()); auto it = lockedNetworks.find(*netMutexMsg->networks.begin());
if (it != lockedNetworks.end()) if (it != lockedNetworks.end())
lockedNetworks.erase(it); lockedNetworks.erase(it);
break; break;
} }
case NetworkMutexEvent::Queued:
break;
} }
} }
}); });
} }
} }
// (re)start the keeponline
keeponline = std::make_unique<Periodic>([this] {
static std::vector<uint8_t> timeoutBytes = std::vector<uint8_t>((uint8_t*)&onlineTimeoutMs, (uint8_t*)&onlineTimeoutMs + sizeof(onlineTimeoutMs));
return com->sendCommand(Command::KeepAlive, timeoutBytes);
}, std::chrono::milliseconds(onlineTimeoutMs / 4));
online = true; online = true;
// restart the heartbeat in online mode
restartHeartbeat();
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOnline(); return true; });
return true; return true;
} }
bool Device::goOffline() { bool Device::goOffline() {
online = false;
keeponline.reset(); keeponline.reset();
// restart the heartbeat in offline mode
restartHeartbeat();
if(networkMutexCallbackHandle) if(networkMutexCallbackHandle)
removeMessageCallback(*networkMutexCallbackHandle); removeMessageCallback(*networkMutexCallbackHandle);
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onGoOffline(); return true; });
if(isDisconnected()) { if(isDisconnected()) {
online = false;
return true; return true;
} }
@@ -625,8 +540,6 @@ bool Device::goOffline() {
updateLEDState(); updateLEDState();
online = false;
return true; return true;
} }
@@ -737,15 +650,17 @@ bool Device::uploadCoremini(std::istream& stream, Disk::MemoryType memType) {
return false; return false;
} }
auto connected = isLogicalDiskConnected(); if (memType == Disk::MemoryType::SD) {
auto connected = isLogicalDiskConnected();
if(!connected) {
return false; // Already added an API error if(!connected) {
} return false; // Already added an API error
}
if(!(*connected)) {
report(APIEvent::Type::DiskNotConnected, APIEvent::Severity::Error); if(!(*connected)) {
return false; report(APIEvent::Type::DiskNotConnected, APIEvent::Severity::Error);
return false;
}
} }
if(!stopScript()) { if(!stopScript()) {
@@ -756,7 +671,6 @@ bool Device::uploadCoremini(std::istream& stream, Disk::MemoryType memType) {
return false; return false;
} }
if(!eraseScriptMemory(memType, static_cast<uint64_t>(bin.size()))) { if(!eraseScriptMemory(memType, static_cast<uint64_t>(bin.size()))) {
return false; return false;
} }
@@ -846,10 +760,12 @@ std::optional<CoreminiHeader> Device::readCoreminiHeader(Disk::MemoryType memTyp
return std::nullopt; return std::nullopt;
} }
auto connected = isLogicalDiskConnected(); if (memType == Disk::MemoryType::SD) {
auto connected = isLogicalDiskConnected();
if(!connected) {
return std::nullopt; // Already added an API error if(!connected) {
return std::nullopt; // Already added an API error
}
} }
#pragma pack(push, 2) #pragma pack(push, 2)
@@ -1008,6 +924,36 @@ std::shared_ptr<HardwareInfo> Device::getHardwareInfo(std::chrono::milliseconds
return hardwareInfo; return hardwareInfo;
} }
std::shared_ptr<MfgConfigMessage> Device::getMfgConfig() {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullptr;
}
std::vector<uint8_t> payload = MfgConfigMessage::EncodeArgumentsForGet();
auto response = com->waitForMessageSync(
[this, payload]() {
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
},
std::make_shared<MessageFilter>(Message::Type::MfgConfig),
std::chrono::milliseconds(250)
);
if(!response) {
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
return nullptr;
}
auto mfgConfig = std::dynamic_pointer_cast<MfgConfigMessage>(response);
if(!mfgConfig) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return nullptr;
}
return mfgConfig;
}
std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, Disk::MemoryType memType) { std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, Disk::MemoryType memType) {
if(!into || timeout <= std::chrono::milliseconds(0)) { if(!into || timeout <= std::chrono::milliseconds(0)) {
@@ -1985,11 +1931,9 @@ void Device::stopScriptStatusThreadIfNecessary(std::unique_lock<std::mutex> lk)
} }
Lifetime Device::suppressDisconnects() { Lifetime Device::suppressDisconnects() {
std::lock_guard<std::mutex> lk(heartbeatMutex); stopHeartbeat();
heartbeatSuppressedByUser++;
return Lifetime([this] { return Lifetime([this] {
std::lock_guard<std::mutex> lk2(heartbeatMutex); startHeartbeat();
heartbeatSuppressedByUser--;
}); });
} }
@@ -2125,6 +2069,18 @@ std::optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message,
return std::make_optional<EthPhyMessage>(*retMsg); return std::make_optional<EthPhyMessage>(*retMsg);
} }
bool Device::sendSPIPortKeyOperation(uint8_t portIndex, SPIPortKeyMessage::Operation op, std::array<uint8_t, 16> key) {
std::vector<uint8_t> args(sizeof(SPIPortKeyMessage::SPIPortKeyPacket));
auto& params = *reinterpret_cast<SPIPortKeyMessage::SPIPortKeyPacket*>(args.data());
params.op = op;
params.portIndex = portIndex;
std::copy(key.begin(), key.end(), params.key);
if(!com->sendCommand(ExtendedCommand::ExecuteSPIPortKeyOperation, args)) {
return false;
}
return true;
}
std::optional<bool> Device::SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress) std::optional<bool> Device::SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress)
{ {
if(!supportsWiVI()) if(!supportsWiVI())
@@ -2263,13 +2219,34 @@ std::optional<std::vector<uint8_t>> Device::getPCBSerial() {
return std::vector<uint8_t>(serialMsg->pcbSerial, serialMsg->pcbSerial + sizeof(serialMsg->pcbSerial)); return std::vector<uint8_t>(serialMsg->pcbSerial, serialMsg->pcbSerial + sizeof(serialMsg->pcbSerial));
} }
std::optional<std::vector<uint8_t>> Device::getMACAddress() { std::unordered_map<Network::NetID, MACAddress> Device::getMACAddresses() {
auto serialMsg = com->getSerialNumberSync(); if(supportsGetAllMACAddresses()) {
if(!serialMsg || !serialMsg->hasMacAddress) { if(!isOpen()) {
return std::nullopt; report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return {};
}
auto msg = com->waitForMessageSync(
[this](){ return com->sendCommand(ExtendedCommand::GetAllMACAddresses, {}); },
std::make_shared<MessageFilter>(Message::Type::AllMACAddresses),
std::chrono::milliseconds(100)
);
if(msg) {
const auto typed = std::dynamic_pointer_cast<AllMACAddressesMessage>(msg);
if(typed)
return typed->addresses;
}
} }
return std::vector<uint8_t>(serialMsg->macAddress, serialMsg->macAddress + sizeof(serialMsg->macAddress)); auto serialMsg = com->getSerialNumberSync();
if(!serialMsg || !serialMsg->hasMacAddress)
return {};
std::unordered_map<Network::NetID, MACAddress> addresses;
auto addr = serialMsg->macAddress;
MACAddress arrAddr;
std::copy(addr, addr + MACAddressLength, arrAddr.begin());
addresses.emplace(std::make_pair(Network::NetID::ETHERNET_01, arrAddr));
return addresses;
} }
std::optional<std::set<SupportedFeature>> Device::getSupportedFeatures() { std::optional<std::set<SupportedFeature>> Device::getSupportedFeatures() {
@@ -3273,11 +3250,12 @@ bool Device::findVSAOffsetFromTimepoint(ICSClock::time_point point, uint64_t& vs
std::shared_ptr<VSA> midRecord; std::shared_ptr<VSA> midRecord;
auto midRecordStatus = parser.getRecordFromBytes(buffer.data(), Disk::SectorSize, midRecord); auto midRecordStatus = parser.getRecordFromBytes(buffer.data(), Disk::SectorSize, midRecord);
switch(midRecordStatus) { switch(midRecordStatus) {
case VSAParser::RecordParseStatus::NotARecordStart: case VSAParser::RecordParseStatus::NotARecordStart: {
// This part of the buffer does not contain records // This part of the buffer does not contain records
rightIndex = midIndex - 1; rightIndex = midIndex - 1;
continue; continue;
case VSAParser::RecordParseStatus::ConsecutiveExtended: }
case VSAParser::RecordParseStatus::ConsecutiveExtended: {
// We dropped in the middle of an extended message record // We dropped in the middle of an extended message record
auto extendedRecord = std::dynamic_pointer_cast<VSAExtendedMessage>(midRecord); auto extendedRecord = std::dynamic_pointer_cast<VSAExtendedMessage>(midRecord);
uint64_t pos = readPos; uint64_t pos = readPos;
@@ -3292,6 +3270,9 @@ bool Device::findVSAOffsetFromTimepoint(ICSClock::time_point point, uint64_t& vs
midIndex = (pos - firstOffset) / Disk::SectorSize; midIndex = (pos - firstOffset) / Disk::SectorSize;
midRecord = extendedRecord; midRecord = extendedRecord;
break; break;
}
default:
break;
} }
if(midIndex <= leftIndex) { if(midIndex <= leftIndex) {
// Extended records cause problems with binary search // Extended records cause problems with binary search
@@ -3714,6 +3695,15 @@ bool Device::requestTC10Sleep(Network::NetID network) {
return typed->response == ExtendedResponse::OK; return typed->response == ExtendedResponse::OK;
} }
bool Device::reboot(bool safe) {
if(!supportsReboot()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false;
}
// The device reboots in response to this command, so no reply is expected.
return com->sendCommand(ExtendedCommand::Reboot, { uint8_t(safe ? 1 : 0) });
}
std::optional<TC10StatusMessage> Device::getTC10Status(Network::NetID network) { std::optional<TC10StatusMessage> Device::getTC10Status(Network::NetID network) {
if(!supportsTC10()) { if(!supportsTC10()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
@@ -4123,3 +4113,270 @@ bool Device::unlockAllNetworks()
return true; return true;
} }
void Device::startHeartbeat() {
if(!heartbeat)
heartbeat = std::make_unique<Heartbeat>(*this);
}
void Device::stopHeartbeat() {
heartbeat.reset();
}
void Device::restartHeartbeat() {
stopHeartbeat();
startHeartbeat();
}
bool Device::iso15765Enable(const Network& network) {
return J2534_EnableIso15765(network, true);
}
bool Device::iso15765DisableAll(void) {
bool ok = true;
for(const auto& slot : iso15765FirmwareEnabled)
{
if (slot.second)
{
if (!J2534_EnableIso15765(slot.first, false))
ok = false;
}
}
return ok;
}
bool Device::iso15765TransmitMessage(const Network& network, const Iso15765MessageArgs& msg, const std::chrono::milliseconds& timeout) {
if (!isOnline())
return false;
if(iso15765FirmwareEnabled.find(network) == iso15765FirmwareEnabled.end() || !iso15765FirmwareEnabled[network])
return false;
bool result;
Iso15765TxSetupMessage setupMsg;
//Set the network ID to use
if(const auto& coreMiniId = network.getCoreMini())
setupMsg.setCoreMiniId((uint16_t)*coreMiniId);
const uint8_t txIndex = msg.getTxIndex();
setupMsg.setIdx(txIndex);
setupMsg.setId(msg.getArbId().Id);
setupMsg.setFcId(msg.getFlowControlArbId().Id);
setupMsg.setFcIdMask(msg.getFlowControlArbIdMask());
setupMsg.setFsTimeout(msg.getFsTimeout());
setupMsg.setFsWait(msg.getFsWaitTimeout());
const uint32_t messageLength = (uint32_t)msg.getData().size();
setupMsg.setMessageLength(messageLength);
setupMsg.setIs29BitEnabled(msg.getArbId().Is29Bit);
setupMsg.setIsFc29BitEnabled(msg.getFlowControlArbId().Is29Bit);
if(const auto& extAddress = msg.getExtendedAddress())
{
setupMsg.setExtAddressEnabled(true);
setupMsg.setExtendedAddress(*extAddress);
}
if(const auto& extFcAddress = msg.getFlowControlExtendedAddress())
{
setupMsg.setFcExtAddressEnabled(true);
setupMsg.setFlowControlExtendedAddress(*extFcAddress);
}
if(const auto& stMin = msg.getStMin())
{
setupMsg.setOverrideStMin(true);
setupMsg.setStMin(*stMin);
}
if(const auto& blockSize = msg.getBlockSize())
{
setupMsg.setOverrideBlockSize(true);
setupMsg.setBlockSize(*blockSize);
}
if(const auto& padding = msg.getPaddingValue())
{
setupMsg.setPaddingEnabled(true);
setupMsg.setPadding(*padding);
}
setupMsg.setIsBrsEnabled(msg.getIsBrsEnabled());
setupMsg.setIsCanFd(msg.getIsCanFd());
setupMsg.setTxDl(msg.getTxDl());
{
uint32_t octetsToSend = messageLength;
const uint8_t* payload = msg.getData().data();
uint32_t offset = 0;
result = J2534_Transaction(network, std::move(setupMsg), timeout);
while(result && octetsToSend)
{
const uint16_t chunkSize = (uint16_t)std::min((uint32_t)Iso15765TxDataMessage::MaxDataLength, octetsToSend);
Iso15765TxDataMessage dataMsg;
dataMsg.setIdx(txIndex);
dataMsg.setOffset(offset);
dataMsg.setData(&payload[offset], chunkSize);
result = J2534_Transaction(network, std::move(dataMsg), timeout);
offset += chunkSize;
octetsToSend -= chunkSize;
}
}
return result;
}
bool Device::iso15765SetupRxFlowControl(const Network& network, const Iso15765MessageArgs& msg) {
if (!isOnline())
return false;
if(iso15765FirmwareEnabled.find(network) == iso15765FirmwareEnabled.end() || !iso15765FirmwareEnabled[network])
return false;
J2534SetupIso15765FlowControlMessage rxFlowControl;
rxFlowControl.setIsBrsEnabled(msg.getIsBrsEnabled());
rxFlowControl.setIsCanFd(msg.getIsCanFd());
rxFlowControl.setIdx(msg.getTxIndex());
if(const auto& coreMiniId = network.getCoreMini())
rxFlowControl.setCoreMiniId((uint16_t)*coreMiniId);
rxFlowControl.setEnable(true);
if(const auto& blockSize = msg.getBlockSize())
{
rxFlowControl.setBlockSize(*blockSize);
}
rxFlowControl.setCfTimeout(msg.getCfTimeout());
rxFlowControl.setFlowControlTransmissionEnabled(msg.getIsFlowControlEnabled());
if(const auto& extAddress = msg.getExtendedAddress())
{
rxFlowControl.setExtendedAddress(*extAddress);
rxFlowControl.setExtAddressEnabled(true);
}
if(const auto& fcExtAddress = msg.getFlowControlExtendedAddress())
{
rxFlowControl.setFlowControlExtendedAddress(*fcExtAddress);
rxFlowControl.setFcExtAddressEnabled(true);
}
rxFlowControl.setFcId(msg.getFlowControlArbId().Id);
rxFlowControl.setIsFc29BitEnabled(msg.getFlowControlArbId().Is29Bit);
rxFlowControl.setIs29BitEnabled(msg.getArbId().Is29Bit);
rxFlowControl.setId(msg.getArbId().Id);
rxFlowControl.setIdMask(msg.getFlowControlArbIdMask());
if(const auto& padding = msg.getPaddingValue())
{
rxFlowControl.setPadding(*padding);
rxFlowControl.setPaddingEnabled(true);
}
if(const auto& stMin = msg.getStMin())
{
rxFlowControl.setStMin(*stMin);
}
return J2534_Transaction(network, std::move(rxFlowControl), std::chrono::milliseconds(0));
}
bool Device::J2534_Transaction(const Network& network, J2534CommandMessage&& msg, const std::chrono::milliseconds& timeout) {
msg.network = network;
if (timeout.count())
{
static std::shared_ptr<MessageFilter> filter = std::make_shared<Main51MessageFilter>(Command::J2534Command);
const auto& response = com->waitForMessageSync([&](void)
{
return com->sendCommand(msg.command, msg.getArgumentData());
}, filter, timeout);
if (!response)
{
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return false;
}
auto responseMsg = std::dynamic_pointer_cast<Main51Message>(response);
if (!responseMsg || responseMsg->command != Command::J2534Command)
{
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
}
else
{
return com->sendCommand(msg.command, msg.getArgumentData());
}
// NOTE: responseMsg->data.front()
return true;
}
bool Device::J2534_ClearRxFilters(const Network& network)
{
return J2534_Transaction(network, J2534CommandMessage(J2534CommandMessage::J2534Command::SetupClearCanRxFilters, { (uint8_t)0 /* is this necessary? */}), std::chrono::milliseconds(0));
}
bool Device::J2534_SetupCanRxFilter(const Network& network, const J2534_RxCanFilter& rxCanFilter)
{
return J2534_Transaction(network, J2534SetupCanRxFilteringMessage(rxCanFilter), std::chrono::milliseconds(0));
}
bool Device::J2534_EnableFiltering(const Network& network, const bool enable)
{
return J2534_Transaction(network, J2534EnableFilteringMessage(enable), std::chrono::milliseconds(0));
}
bool Device::J2534_EnableIso15765(const Network& network, const bool enable)
{
if (iso15765FirmwareEnabled[network] == enable)
return true;
if (!J2534_Transaction(network, J2534EnableMessage(enable), std::chrono::milliseconds(0)))
return false;
iso15765FirmwareEnabled[network] = enable;
if (enable)
{
// Turn OFF filtering of CAN messages in the firmware
return J2534_EnableFirmwareUsbPassFilters(network, false);
}
return true;
}
bool Device::J2534_ClearRxFilter(const Network& network, unsigned int iIndex)
{
if (const auto& slot = iso15765FirmwareEnabled.find(network); slot != iso15765FirmwareEnabled.end() && slot->second)
{
J2534_RxCanFilter rxFilter;
memset(&rxFilter, 0, sizeof(rxFilter));
rxFilter.idx = (uint16_t)iIndex;
return J2534_SetupCanRxFilter(network, rxFilter);
}
return false;
}
bool Device::J2534_EnableFirmwareUsbPassFilters(const Network& network, const bool enable)
{
const auto& slot = iso15765FirmwareEnabled.find(network);
if (slot == iso15765FirmwareEnabled.end())
return false;
//check for disconnect here!
if (!slot->second)
{
// Tried to shut-off Rx table message filtering but FW ISO15765 was not enabled
return true; //just ignore it, no filtering can occur anyway
}
if (enable) //turning ON filtering in the Firmware based on the rx table
{
//Rx table message filtering is on by default in the firmware when m_bISO15765_FW_Enabled is true
//need to check here to see if we set index 0 to a PASS all filter (i.e. turned off USB filtering)
if (!J2534_ClearRxFilters(network))
return false;
}
// New "filtering enable" mechanism - old firmware ignores this frame
return J2534_EnableFiltering(network, enable);
}
+10 -6
View File
@@ -165,10 +165,6 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADA2B>(dev, newFoundDevices); makeIfSerialMatches<RADA2B>(dev, newFoundDevices);
#endif #endif
#ifdef __RADCOMET_H_
makeIfSerialRangeMatches<RADComet>(dev, newFoundDevices);
#endif
#ifdef __RADCOMET2_H_ #ifdef __RADCOMET2_H_
makeIfSerialRangeMatches<RADComet2>(dev, newFoundDevices); makeIfSerialRangeMatches<RADComet2>(dev, newFoundDevices);
#endif #endif
@@ -245,6 +241,10 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADSupermoon>(dev, newFoundDevices); makeIfSerialMatches<RADSupermoon>(dev, newFoundDevices);
#endif #endif
#ifdef __RADWBMS_H_
makeIfSerialMatches<RADwBMS>(dev, newFoundDevices);
#endif
#ifdef __VALUECAN3_H_ #ifdef __VALUECAN3_H_
makeIfSerialRangeMatches<ValueCAN3>(dev, newFoundDevices); makeIfSerialRangeMatches<ValueCAN3>(dev, newFoundDevices);
#endif #endif
@@ -340,8 +340,8 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADA2B::DEVICE_TYPE, RADA2B::DEVICE_TYPE,
#endif #endif
#ifdef __RADCOMET_H_ #ifdef __RADCOMET2_H_
RADComet::DEVICE_TYPE, RADComet2::DEVICE_TYPE,
#endif #endif
#ifdef __RADCOMET3_H_ #ifdef __RADCOMET3_H_
@@ -408,6 +408,10 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADSupermoon::DEVICE_TYPE, RADSupermoon::DEVICE_TYPE,
#endif #endif
#ifdef __RADWBMS_H_
RADwBMS::DEVICE_TYPE,
#endif
#ifdef __VALUECAN3_H_ #ifdef __VALUECAN3_H_
ValueCAN3::DEVICE_TYPE, ValueCAN3::DEVICE_TYPE,
#endif #endif
+171 -18
View File
@@ -1,9 +1,16 @@
#include "icsneo/device/device.h"
#include "icsneo/device/idevicesettings.h" #include "icsneo/device/idevicesettings.h"
#include "icsneo/communication/message/filter/main51messagefilter.h" #include "icsneo/communication/message/filter/main51messagefilter.h"
#include <cstring> #include <cstring>
using namespace icsneo; using namespace icsneo;
IDeviceSettings::IDeviceSettings(Device* device, size_t size)
: device(device), report(device->report), structSize(size) {}
IDeviceSettings::IDeviceSettings(warn_t createInoperableSettings, Device* device)
: disabled(true), readonly(true), report(device->report), structSize(0) { (void)createInoperableSettings; }
std::optional<uint16_t> IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& settings) { std::optional<uint16_t> IDeviceSettings::CalculateGSChecksum(const std::vector<uint8_t>& settings) {
const uint16_t* p = reinterpret_cast<const uint16_t*>(settings.data()); const uint16_t* p = reinterpret_cast<const uint16_t*>(settings.data());
size_t words = settings.size(); size_t words = settings.size();
@@ -166,7 +173,7 @@ bool IDeviceSettings::refresh() {
} }
std::vector<uint8_t> rxSettings; std::vector<uint8_t> rxSettings;
bool ret = com->getSettingsSync(rxSettings); bool ret = device->com->getSettingsSync(rxSettings);
if(!ret) { if(!ret) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error); report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false; return false;
@@ -231,10 +238,10 @@ bool IDeviceSettings::apply(bool temporary) {
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
// Pause I/O with the device while the settings are applied // Pause I/O with the device while the settings are applied
applyingSettings = true; device->stopHeartbeat();
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return device->com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { // We did not receive a response if(!msg || msg->data[0] != 1) { // We did not receive a response
@@ -259,8 +266,8 @@ bool IDeviceSettings::apply(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return device->com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -272,12 +279,12 @@ bool IDeviceSettings::apply(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return device->com->sendCommand(Command::SaveSettings);
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; device->startHeartbeat();
refresh(); // Refresh our buffer with what the device has, whether we were successful or not refresh(); // Refresh our buffer with what the device has, whether we were successful or not
@@ -299,10 +306,10 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
return false; return false;
} }
applyingSettings = true; device->stopHeartbeat();
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings); return device->com->sendCommand(Command::SetDefaultSettings);
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -336,8 +343,8 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return device->com->sendCommand(Command::SetSettings, bytestream);
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(5000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@@ -349,12 +356,12 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(device->com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return device->com->sendCommand(Command::SaveSettings);
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000))); }, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; device->startHeartbeat();
refresh(); // Refresh our buffer with what the device has, whether we were successful or not refresh(); // Refresh our buffer with what the device has, whether we were successful or not
@@ -959,4 +966,150 @@ bool IDeviceSettings::setMiscIOAnalogOutput(uint8_t pin, MiscIOAnalogVoltage vol
(void)voltage; (void)voltage;
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error); report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error);
return false; return false;
} }
std::optional<RADGPTPProfile> IDeviceSettings::getGPTPProfile() const {
const auto* gptp = getGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
return static_cast<RADGPTPProfile>(gptp->profile);
}
bool IDeviceSettings::setGPTPProfile(RADGPTPProfile profile) {
auto* gptp = getMutableGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return false;
}
gptp->profile = static_cast<uint8_t>(profile);
return true;
}
std::optional<RADGPTPRole> IDeviceSettings::getGPTPRole() const {
const auto* gptp = getGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
return static_cast<RADGPTPRole>(gptp->gptpPortRole);
}
bool IDeviceSettings::setGPTPRole(RADGPTPRole role) {
auto* gptp = getMutableGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return false;
}
gptp->gptpPortRole = static_cast<uint8_t>(role);
return true;
}
std::optional<uint8_t> IDeviceSettings::getGPTPEnabledPort() const {
const auto* gptp = getGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
return gptp->gptpEnabledPort;
}
bool IDeviceSettings::setGPTPEnabledPort(uint8_t port) {
auto* gptp = getMutableGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return false;
}
gptp->gptpEnabledPort = port;
return true;
}
std::optional<bool> IDeviceSettings::isGPTPClockSyntonizationEnabled() const {
const auto* gptp = getGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
return gptp->enableClockSyntonization != 0;
}
bool IDeviceSettings::setGPTPClockSyntonizationEnabled(bool enable) {
auto* gptp = getMutableGPTPSettings();
if(!gptp) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return false;
}
gptp->enableClockSyntonization = enable ? 1 : 0;
return true;
}
std::optional<bool> IDeviceSettings::getLinuxBootEnabled() {
const auto* os = getLinuxSettings();
if(os == nullptr) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
return os->allowBoot != 0;
}
bool IDeviceSettings::setLinuxBootEnabled(bool enabled) {
auto os = getMutableLinuxSettings();
if(!os) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error);
return false;
}
(*os)->allowBoot = enabled ? 1 : 0;
return true;
}
std::optional<bool> IDeviceSettings::getExternalWifiAntennaEnabled() {
const auto* os = getLinuxSettings();
if(os == nullptr) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
return os->useExternalWifiAntenna != 0;
}
bool IDeviceSettings::setExternalWifiAntennaEnabled(bool enabled) {
auto os = getMutableLinuxSettings();
if(!os) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error);
return false;
}
(*os)->useExternalWifiAntenna = enabled ? 1 : 0;
return true;
}
std::optional<LinuxConfigurationPort> IDeviceSettings::getLinuxConfigurationPort() {
const auto* os = getLinuxSettings();
if(os == nullptr) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::EventWarning);
return std::nullopt;
}
switch(static_cast<LinuxConfigurationPort>(os->ethConfigurationPort)) {
case LinuxConfigurationPort::ETH01:
return LinuxConfigurationPort::ETH01;
case LinuxConfigurationPort::USB:
default: // Any other value means the configuration interface is over USB
return LinuxConfigurationPort::USB;
}
}
bool IDeviceSettings::setLinuxConfigurationPort(LinuxConfigurationPort port) {
switch(port) {
case LinuxConfigurationPort::USB:
case LinuxConfigurationPort::ETH01:
break;
default:
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
auto os = getMutableLinuxSettings();
if(!os) {
report(APIEvent::Type::SettingNotAvaiableDevice, APIEvent::Severity::Error);
return false;
}
(*os)->ethConfigurationPort = static_cast<uint8_t>(port);
return true;
}
+40
View File
@@ -10,6 +10,14 @@ Simple
.. literalinclude:: ../../examples/c2/simple/src/main.c .. literalinclude:: ../../examples/c2/simple/src/main.c
:language: c :language: c
Supported Devices
=================
:download:`Download example <../../examples/c2/supported_devices/src/main.c>`
.. literalinclude:: ../../examples/c2/supported_devices/src/main.c
:language: c
Disk Format Disk Format
=========== ===========
@@ -66,6 +74,14 @@ Ethernet Receive
.. literalinclude:: ../../examples/c2/ethernet_receive/src/main.c .. literalinclude:: ../../examples/c2/ethernet_receive/src/main.c
:language: c :language: c
Ethernet Status
===============
:download:`Download example <../../examples/c2/ethernet_status/src/main.c>`
.. literalinclude:: ../../examples/c2/ethernet_status/src/main.c
:language: c
T1S Loopback T1S Loopback
============ ============
@@ -82,3 +98,27 @@ TC10
.. literalinclude:: ../../examples/c2/tc10/src/main.c .. literalinclude:: ../../examples/c2/tc10/src/main.c
:language: c :language: c
gPTP
====
:download:`Download example <../../examples/c2/gptp/src/main.c>`
.. literalinclude:: ../../examples/c2/gptp/src/main.c
:language: c
PerfTest
========
:download:`Download example <../../examples/c2/perf_test/src/main.c>`
.. literalinclude:: ../../examples/c2/perf_test/src/main.c
:language: c
Termination Groups
==================
:download:`Download example <../../examples/c2/termination/src/main.c>`
.. literalinclude:: ../../examples/c2/termination/src/main.c
:language: c
+1 -1
View File
@@ -127,7 +127,7 @@ FlexRay Coldstart Configuration
To use the Coldstart example, ensure the following: To use the Coldstart example, ensure the following:
Set the Flexray network in neoVI Explorer to Coldstart. Set the Flexray network in ICS Device Manager to Coldstart.
No other nodes should be present on the network during testing. No other nodes should be present on the network during testing.
+45
View File
@@ -2,17 +2,24 @@ option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive
option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON) option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON) option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the simple C2 example." ON) option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the simple C2 example." ON)
option(LIBICSNEO_BUILD_C2_SUPPORTED_DEVICES_EXAMPLE "Build the C2 supported devices example." ON)
option(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE "Build the C2 read messages 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_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_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_DEVICE_INFO_EXAMPLE "Build the C2 device info example." ON)
option(LIBICSNEO_BUILD_C2_CHIP_VERSIONS_EXAMPLE "Build the C2 chip versions example." ON)
option(LIBICSNEO_BUILD_C2_TERMINATION_EXAMPLE "Build the C2 termination groups example." ON)
option(LIBICSNEO_BUILD_C2_LIN_EXAMPLE "Build the C2 LIN 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_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_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_ETHERNET_RECEIVE_EXAMPLE "Build the C2 ethernet receive example." ON)
option(LIBICSNEO_BUILD_C2_ETHERNET_STATUS_EXAMPLE "Build the C2 ethernet status example." ON)
option(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE "Build the C2 RAD-Comet3 T1S loopback 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_C2_TC10_EXAMPLE "Build the C2 TC10 example." ON)
option(LIBICSNEO_BUILD_C2_GPTP_EXAMPLE "Build the C2 gPTP settings example." ON)
option(LIBICSNEO_BUILD_C2_PERF_TEST_EXAMPLE "Build the C2 PerfTest setting example." ON)
option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON) option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
option(LIBICSNEO_BUILD_CPP_DEVICE_INFO_EXAMPLE "Build the C++ device info example." ON)
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON) option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON) option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON) option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON)
@@ -28,6 +35,8 @@ 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_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_DISKFORMAT_EXAMPLE "Build the disk format example." ON)
option(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE "Build the T1S example." ON) option(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE "Build the T1S example." ON)
option(LIBICSNEO_BUILD_CPP_GPTP_EXAMPLE "Build the C++ gPTP settings example." ON)
option(LIBICSNEO_BUILD_CPP_ISO15765_LOOPBACK_EXAMPLE "Build the C++ ISO15765 two-device CAN1 loopback example." ON)
add_compile_options(${LIBICSNEO_COMPILER_WARNINGS}) add_compile_options(${LIBICSNEO_COMPILER_WARNINGS})
@@ -47,6 +56,10 @@ if(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE)
add_subdirectory(c2/simple) add_subdirectory(c2/simple)
endif() endif()
if(LIBICSNEO_BUILD_C2_SUPPORTED_DEVICES_EXAMPLE)
add_subdirectory(c2/supported_devices)
endif()
if(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE) if(LIBICSNEO_BUILD_C2_READ_MESSAGES_EXAMPLE)
add_subdirectory(c2/read_messages) add_subdirectory(c2/read_messages)
endif() endif()
@@ -63,6 +76,14 @@ if(LIBICSNEO_BUILD_C2_DEVICE_INFO_EXAMPLE)
add_subdirectory(c2/device_info) add_subdirectory(c2/device_info)
endif() endif()
if(LIBICSNEO_BUILD_C2_CHIP_VERSIONS_EXAMPLE)
add_subdirectory(c2/chip_versions)
endif()
if(LIBICSNEO_BUILD_C2_TERMINATION_EXAMPLE)
add_subdirectory(c2/termination)
endif()
if(LIBICSNEO_BUILD_C2_LIN_EXAMPLE) if(LIBICSNEO_BUILD_C2_LIN_EXAMPLE)
add_subdirectory(c2/lin) add_subdirectory(c2/lin)
endif() endif()
@@ -79,6 +100,10 @@ if(LIBICSNEO_BUILD_C2_ETHERNET_RECEIVE_EXAMPLE)
add_subdirectory(c2/ethernet_receive) add_subdirectory(c2/ethernet_receive)
endif() endif()
if(LIBICSNEO_BUILD_C2_ETHERNET_STATUS_EXAMPLE)
add_subdirectory(c2/ethernet_status)
endif()
if(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE) if(LIBICSNEO_BUILD_C2_T1S_LOOPBACK_EXAMPLE)
add_subdirectory(c2/t1s_loopback) add_subdirectory(c2/t1s_loopback)
endif() endif()
@@ -87,10 +112,22 @@ if(LIBICSNEO_BUILD_C2_TC10_EXAMPLE)
add_subdirectory(c2/tc10) add_subdirectory(c2/tc10)
endif() endif()
if(LIBICSNEO_BUILD_C2_GPTP_EXAMPLE)
add_subdirectory(c2/gptp)
endif()
if(LIBICSNEO_BUILD_C2_PERF_TEST_EXAMPLE)
add_subdirectory(c2/perf_test)
endif()
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE) if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
add_subdirectory(cpp/simple) add_subdirectory(cpp/simple)
endif() endif()
if(LIBICSNEO_BUILD_CPP_DEVICE_INFO_EXAMPLE)
add_subdirectory(cpp/device_info)
endif()
if(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE) if(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE)
add_subdirectory(cpp/interactive) add_subdirectory(cpp/interactive)
endif() endif()
@@ -150,3 +187,11 @@ endif()
if(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE) if(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE)
add_subdirectory(cpp/t1s) add_subdirectory(cpp/t1s)
endif() endif()
if(LIBICSNEO_BUILD_CPP_GPTP_EXAMPLE)
add_subdirectory(cpp/gptp)
endif()
if(LIBICSNEO_BUILD_CPP_ISO15765_LOOPBACK_EXAMPLE)
add_subdirectory(cpp/iso15765_loopback)
endif()
+5 -5
View File
@@ -58,7 +58,7 @@ int main() {
msg1.Protocol = SPY_PROTOCOL_LIN; msg1.Protocol = SPY_PROTOCOL_LIN;
msg1.StatusBitField = 0; msg1.StatusBitField = 0;
msg1.StatusBitField2 = 0; msg1.StatusBitField2 = 0;
lNetworkID = NETID_LIN_02; lNetworkID = NETID_LIN2;
msg1.Header[0] = 0x11; //protected ID msg1.Header[0] = 0x11; //protected ID
msg1.Header[1] = 0xaa; msg1.Header[1] = 0xaa;
msg1.Header[2] = 0xbb; msg1.Header[2] = 0xbb;
@@ -80,7 +80,7 @@ int main() {
icsSpyMessageJ1850 msg2 = {0}; icsSpyMessageJ1850 msg2 = {0};
msg2.Protocol = SPY_PROTOCOL_LIN; msg2.Protocol = SPY_PROTOCOL_LIN;
msg2.StatusBitField = SPY_STATUS_INIT_MESSAGE; msg2.StatusBitField = SPY_STATUS_INIT_MESSAGE;
lNetworkID = NETID_LIN_01; lNetworkID = NETID_LIN;
msg2.Header[0] = 0x11; //protected ID msg2.Header[0] = 0x11; //protected ID
msg2.NumberBytesData = 0; msg2.NumberBytesData = 0;
msg2.NumberBytesHeader = 1; msg2.NumberBytesHeader = 1;
@@ -96,7 +96,7 @@ int main() {
msg3.Protocol = SPY_PROTOCOL_LIN; msg3.Protocol = SPY_PROTOCOL_LIN;
msg3.StatusBitField = SPY_STATUS_INIT_MESSAGE; msg3.StatusBitField = SPY_STATUS_INIT_MESSAGE;
msg3.StatusBitField2 = 0; msg3.StatusBitField2 = 0;
lNetworkID = NETID_LIN_01; lNetworkID = NETID_LIN;
msg3.Header[0] = 0xe2; //protected ID msg3.Header[0] = 0xe2; //protected ID
msg3.Header[1] = 0x44; msg3.Header[1] = 0x44;
msg3.Header[2] = 0x33; msg3.Header[2] = 0x33;
@@ -131,10 +131,10 @@ int main() {
const icsSpyMessageJ1850* linMsg = (icsSpyMessageJ1850*)&rxMsg[idx]; const icsSpyMessageJ1850* linMsg = (icsSpyMessageJ1850*)&rxMsg[idx];
size_t frameLen = (linMsg->NumberBytesHeader + linMsg->NumberBytesData); size_t frameLen = (linMsg->NumberBytesHeader + linMsg->NumberBytesData);
size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0; size_t dataLen = (frameLen > 2) ? (frameLen - 2) : 0;
if(linMsg->NetworkID == NETID_LIN_01) { if(linMsg->NetworkID == NETID_LIN) {
printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen); printf("LIN 1 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen);
} }
else if (linMsg->NetworkID == NETID_LIN_02) { else if (linMsg->NetworkID == NETID_LIN2) {
printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen); printf("LIN 2 | ID: 0x%02x [%zu] ", linMsg->Header[0], dataLen);
} }
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-chip-versions-example src/main.c)
target_link_libraries(libicsneoc2-chip-versions-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-chip-versions-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+59
View File
@@ -0,0 +1,59 @@
#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 %u with error code %u\n", message, error, res);
return (int)res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
int main() {
icsneoc2_error_t res;
icsneoc2_device_t* device = NULL;
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);
}
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);
size_t count = 0;
icsneoc2_chip_versions_t* chip_versions = NULL;
res = icsneoc2_device_chip_versions_enumerate(device, &chip_versions, true, &count);
if(res != icsneoc2_error_success) {
print_error_code("Failed to enumerate chip versions", res);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
printf("Found %zu chip version(s):\n", count);
for(icsneoc2_chip_versions_t* cur = chip_versions; cur; cur = icsneoc2_chip_versions_next(cur)) {
char name[64] = {0};
size_t name_length = sizeof(name);
uint8_t major = 0, minor = 0, maintenance = 0, build = 0;
res = icsneoc2_chip_versions_props_get(cur, name, &name_length, &major, &minor, &maintenance, &build);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get chip version properties", res);
continue;
}
printf(" %s: %u.%u.%u.%u\n", name, major, minor, maintenance, build);
}
icsneoc2_chip_versions_free(chip_versions);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
+22 -10
View File
@@ -102,19 +102,31 @@ int main() {
print_error_code("Failed to get PCB serial (device may not support it)", res); print_error_code("Failed to get PCB serial (device may not support it)", res);
} }
/* ===== MAC Address ===== */ /* ===== MAC Addresses ===== */
uint8_t mac[6] = {0}; icsneoc2_mac_addr_entry_t* macs = NULL;
size_t mac_len = sizeof(mac); res = icsneoc2_device_mac_addresses_enumerate(device, &macs);
res = icsneoc2_device_mac_address_get(device, mac, &mac_len);
if(res == icsneoc2_error_success) { if(res == icsneoc2_error_success) {
printf("MAC: "); uint16_t mac_count = 0;
for(size_t i = 0; i < mac_len; i++) { for(icsneoc2_mac_addr_entry_t* cur = macs; cur; cur = icsneoc2_mac_addresses_next(cur)) {
if(i > 0) printf(":"); mac_count++;
printf("%02X", mac[i]);
} }
printf("\n"); printf("MACs: %u entr%s\n", mac_count, mac_count == 1 ? "y" : "ies");
for(icsneoc2_mac_addr_entry_t* cur = macs; cur; cur = icsneoc2_mac_addresses_next(cur)) {
icsneoc2_netid_t network_id;
icsneoc2_mac_network_id_get(cur, &network_id);
printf(" Network %-5u ", (unsigned)network_id);
uint8_t address[6];
size_t address_size = 6;
icsneoc2_mac_address_get(cur, address, &address_size);
for(int j = 0; j < 6; j++) {
if(j > 0) printf(":");
printf("%02X", (unsigned)address[j]);
}
printf("\n");
}
icsneoc2_mac_addresses_free(macs);
} else { } else {
print_error_code("Failed to get MAC address (device may not support it)", res); print_error_code("Failed to get MAC addresses (device may not support it)", res);
} }
/* Cleanup */ /* Cleanup */
+79
View File
@@ -109,6 +109,85 @@ int main() {
} }
} }
/* Choose operation */
printf("\n\tChoose operation:\n");
printf("\t [f] Format the disk(s)\n");
printf("\t [u] Update the disk configuration without formatting\n");
printf("\t [q] Quit\n");
printf("\tSelection [f/u/q]: ");
char choice[8] = {0};
if(scanf("%7s", choice) != 1) {
choice[0] = 'q';
}
if(choice[0] == 'u' || choice[0] == 'U') {
/* Force a disk config update (e.g. changing the disk layout) without formatting.
* Unlike a format, this preserves the existing data on the disk(s). */
printf("\n\tChoose disk layout:\n");
printf("\t [s] Spanned\n");
printf("\t [r] RAID0\n");
printf("\tSelection [s/r] (current: %s): ", layout == icsneoc2_disk_layout_raid0 ? "RAID0" : "Spanned");
char layout_choice[8] = {0};
if(scanf("%7s", layout_choice) != 1) {
layout_choice[0] = '\0';
}
if(layout_choice[0] == 'r' || layout_choice[0] == 'R') {
icsneoc2_disk_details_layout_set(details, icsneoc2_disk_layout_raid0);
} else if(layout_choice[0] == 's' || layout_choice[0] == 'S') {
icsneoc2_disk_details_layout_set(details, icsneoc2_disk_layout_spanned);
} else {
printf("\tKeeping current layout.\n");
}
/* Enable/disable individual disks in the configuration. A disk's enabled
* state is carried by the FORMATTED flag; only present disks can be enabled. */
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)) {
continue; /* Can't enable a disk that isn't present */
}
printf("\tEnable disk [%zu]? [y/N] (currently %s): ", i,
(flags & ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED) ? "enabled" : "disabled");
char disk_choice[8] = {0};
if(scanf("%7s", disk_choice) != 1) {
disk_choice[0] = '\0';
}
if(disk_choice[0] == 'y' || disk_choice[0] == 'Y') {
flags |= ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED;
} else {
flags &= ~(icsneoc2_disk_format_flags_t)ICSNEOC2_DISK_FORMAT_FLAGS_FORMATTED;
}
icsneoc2_disk_details_flags_set(details, i, flags);
}
icsneoc2_disk_layout_t new_layout = 0;
icsneoc2_disk_details_layout_get(details, &new_layout);
printf("\n\tForcing disk config update on %s to %s layout (no data will be erased)...\n",
description, new_layout == icsneoc2_disk_layout_raid0 ? "RAID0" : "Spanned");
res = icsneoc2_device_force_disk_config_update(device, details);
if(res != icsneoc2_error_success) {
print_error_code("\tForce disk config update failed", res);
icsneoc2_disk_details_free(details);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return -1;
}
printf("\tDisk config update complete!\n");
icsneoc2_disk_details_free(details);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
if(choice[0] != 'f' && choice[0] != 'F') {
printf("\tAborted.\n");
icsneoc2_disk_details_free(details);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
/* Build format config: mark present disks for formatting */ /* Build format config: mark present disks for formatting */
bool any_present = false; bool any_present = false;
for(size_t i = 0; i < detail_count; i++) { for(size_t i = 0; i < detail_count; i++) {
+6
View File
@@ -68,6 +68,7 @@ void print_mac(const char* label, const uint8_t* mac) {
int process_ethernet_message(icsneoc2_message_t* message, size_t index) { int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
uint64_t timestamp = 0;
char netid_name[128] = {0}; char netid_name[128] = {0};
size_t netid_name_length = 128; size_t netid_name_length = 128;
@@ -79,6 +80,10 @@ int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get netid name", res); return print_error_code("\tFailed to get netid name", res);
} }
res = icsneoc2_message_timestamp_get(message, &timestamp);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get timestamp", res);
}
/* Get data length first */ /* Get data length first */
size_t data_length = 0; size_t data_length = 0;
@@ -88,6 +93,7 @@ int process_ethernet_message(icsneoc2_message_t* message, size_t index) {
} }
printf("\t%zu) Ethernet Frame on %s (0x%x) - %zu bytes\n", index, netid_name, netid, data_length); printf("\t%zu) Ethernet Frame on %s (0x%x) - %zu bytes\n", index, netid_name, netid, data_length);
printf("\t Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
/* Get MAC addresses and EtherType if we have enough data */ /* Get MAC addresses and EtherType if we have enough data */
uint8_t dst_mac[6] = {0}; uint8_t dst_mac[6] = {0};
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-ethernet-status-example src/main.c)
target_link_libraries(libicsneoc2-ethernet-status-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-ethernet-status-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+228
View File
@@ -0,0 +1,228 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <stdio.h>
#include <time.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] = {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;
}
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 = sizeof(description);
icsneoc2_error_t res = icsneoc2_event_description_get(events[i], description, &description_length);
if(res != icsneoc2_error_success) {
(void)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);
}
}
const char* link_speed_name(icsneoc2_link_speed_t speed) {
switch(speed) {
case icsneoc2_link_speed_auto:
return "Auto";
case icsneoc2_link_speed_10mbps:
return "10 Mbps";
case icsneoc2_link_speed_100mbps:
return "100 Mbps";
case icsneoc2_link_speed_1000mbps:
return "1000 Mbps";
case icsneoc2_link_speed_2500mbps:
return "2500 Mbps";
case icsneoc2_link_speed_5000mbps:
return "5000 Mbps";
case icsneoc2_link_speed_10000mbps:
return "10000 Mbps";
default:
return "Unknown";
}
}
const char* link_mode_name(icsneoc2_link_mode_t mode) {
switch(mode) {
case icsneoc2_link_mode_auto:
return "Auto";
case icsneoc2_link_mode_master:
return "Master";
case icsneoc2_link_mode_slave:
return "Slave";
case icsneoc2_link_mode_invalid:
return "Invalid";
case icsneoc2_link_mode_none:
return "None";
default:
return "Unknown";
}
}
int print_ethernet_status_message(icsneoc2_message_t* message, size_t index) {
icsneoc2_netid_t netid = 0;
char netid_name[128] = {0};
size_t netid_name_length = sizeof(netid_name);
bool link_state = false;
bool duplex = false;
icsneoc2_link_speed_t link_speed = icsneoc2_link_speed_auto;
icsneoc2_link_mode_t link_mode = icsneoc2_link_mode_auto;
icsneoc2_error_t res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get Ethernet status 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 Ethernet status netid name", res);
}
res = icsneoc2_message_eth_status_props_get(message, &link_state, &duplex, &link_speed, &link_mode);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get Ethernet status properties", res);
}
printf("\t%zu) Ethernet status on %s (0x%x)\n", index, netid_name, netid);
printf("\t Link: %s\n", link_state ? "Up" : "Down");
printf("\t Duplex: %s\n", duplex ? "Full" : "Half");
printf("\t Speed: %s (%u)\n", link_speed_name(link_speed), link_speed);
printf("\t Mode: %s (%u)\n", link_mode_name(link_mode), link_mode);
return icsneoc2_error_success;
}
int main(void) {
printf("Opening first available device offline...\n");
icsneoc2_device_t* device = NULL;
icsneoc2_open_options_t options = icsneoc2_open_options_default & ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE;
icsneoc2_error_t res = icsneoc2_device_open_first(0, options, &device);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to open first device", res);
}
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_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to get device description", res);
}
printf("Opened device: %s\n", description);
printf("Going online to trigger Ethernet status broadcast...\n");
res = icsneoc2_device_go_online(device, true);
if(res != icsneoc2_error_success) {
print_events();
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to go online", res);
}
const int listen_seconds = 6;
time_t start_time = time(NULL);
size_t status_count = 0;
size_t total_count = 0;
printf("Listening for Ethernet status messages for %d seconds...\n", listen_seconds);
while(time(NULL) - start_time < listen_seconds) {
icsneoc2_message_t* message = NULL;
res = icsneoc2_device_message_get(device, &message, 100);
if(res != icsneoc2_error_success) {
print_events();
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to get message", res);
}
if(message == NULL) {
sleep_ms(10);
continue;
}
total_count++;
bool is_ethernet_status = false;
res = icsneoc2_message_is_ethernet_status(message, &is_ethernet_status);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return print_error_code("Failed to check for Ethernet status message", res);
}
if(is_ethernet_status) {
res = print_ethernet_status_message(message, status_count);
if(res != icsneoc2_error_success) {
icsneoc2_message_free(message);
print_events();
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return (int)res;
}
status_count++;
}
icsneoc2_message_free(message);
}
printf("Received %zu Ethernet status messages out of %zu total messages.\n", status_count, total_count);
if(status_count == 0) {
printf("No Ethernet status messages were seen. These messages are broadcast when the device goes online and may depend on device Ethernet support.\n");
}
print_events();
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);
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-gptp-example src/main.c)
target_link_libraries(libicsneoc2-gptp-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-gptp-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+330
View File
@@ -0,0 +1,330 @@
/*
* gPTP settings configurator example.
*
* Lists connected devices and their gPTP support, then lets the user
* configure the gPTP profile, role, port, and clock syntonization on any
* device that supports it. If --serial is omitted, the first available
* gPTP-capable device is used.
*/
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2settings.h>
#include <icsneo/icsneoc2messages.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* serial;
bool list;
} args_t;
/* Maps an icsneoc2_netid_t to its gPTP port index (0 = not a gPTP port). */
static uint8_t netid_to_gptp_port(icsneoc2_netid_t netid) {
switch(netid) {
case icsneoc2_netid_ae_01: return 1;
case icsneoc2_netid_ae_02: return 2;
case icsneoc2_netid_ae_03: return 3;
case icsneoc2_netid_ae_04: return 4;
case icsneoc2_netid_ae_05: return 5;
case icsneoc2_netid_ae_06: return 6;
case icsneoc2_netid_ae_07: return 7;
case icsneoc2_netid_ae_08: return 8;
case icsneoc2_netid_ae_09: return 9;
case icsneoc2_netid_ae_10: return 10;
case icsneoc2_netid_ae_11: return 11;
case icsneoc2_netid_ae_12: return 12;
case icsneoc2_netid_ethernet_01: return 13;
case icsneoc2_netid_ethernet_02: return 14;
case icsneoc2_netid_ethernet_03: return 15;
case icsneoc2_netid_ae_13: return 16;
case icsneoc2_netid_ae_14: return 17;
case icsneoc2_netid_ae_15: return 18;
case icsneoc2_netid_ae_16: return 19;
default: return 0;
}
}
static const char* gptp_profile_str(icsneoc2_gptp_profile_t p) {
switch(p) {
case icsneoc2_gptp_profile_standard: return "Standard";
case icsneoc2_gptp_profile_automotive: return "Automotive";
default: return "Unknown";
}
}
static const char* gptp_role_str(icsneoc2_gptp_role_t r) {
switch(r) {
case icsneoc2_gptp_role_disabled: return "Disabled";
case icsneoc2_gptp_role_passive: return "Passive";
case icsneoc2_gptp_role_master: return "Master";
case icsneoc2_gptp_role_slave: return "Slave";
default: return "Unknown";
}
}
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) {
fprintf(stderr, "%s: failed to get string for error code %u\n", message, error);
return (int)res;
}
fprintf(stderr, "%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
static void print_usage(const char* prog) {
printf("Usage:\n");
printf(" %s --list\n", prog);
printf(" %s [--serial SERIAL]\n", prog);
printf("\n");
printf(" --list List connected devices and their gPTP support.\n");
printf(" --serial SERIAL Serial number of the device to configure.\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, "--list") == 0) {
out->list = true;
} 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 {
fprintf(stderr, "error: unknown argument '%s'\n", a);
print_usage(argv[0]);
return 1;
}
}
return 0;
}
static icsneoc2_device_info_t* find_device(icsneoc2_device_info_t* list, const char* serial) {
for(icsneoc2_device_info_t* cur = list; cur != NULL; cur = icsneoc2_device_info_next(cur)) {
if(serial == NULL)
return 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;
}
/*
* Print a list of available Ethernet/AE networks with their gPTP port indices.
* Returns the number of ports printed.
*/
static size_t print_gptp_ports(icsneoc2_device_t* device) {
icsneoc2_netid_t nets[128] = {0};
size_t count = sizeof(nets) / sizeof(nets[0]);
if(icsneoc2_device_supported_tx_networks_get(device, nets, &count) != icsneoc2_error_success)
return 0;
size_t printed = 0;
for(size_t i = 0; i < count; ++i) {
uint8_t port = netid_to_gptp_port(nets[i]);
if(port == 0)
continue;
char name[64] = {0};
size_t name_len = sizeof(name);
icsneoc2_netid_name_get(nets[i], name, &name_len);
printf(" [%u] %s\n", (unsigned)port, name);
++printed;
}
return printed;
}
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);
char description[256] = {0};
size_t description_len = sizeof(description);
icsneoc2_device_info_serial_get(cur, serial, &serial_len);
icsneoc2_device_info_description_get(cur, description, &description_len);
printf("[%zu] %s (%s)\n", index++, description, serial);
icsneoc2_device_t* device = NULL;
if(icsneoc2_device_create(cur, &device) != icsneoc2_error_success)
continue;
icsneoc2_open_options_t opts = icsneoc2_open_options_default;
opts &= ~ICSNEOC2_OPEN_OPTIONS_SYNC_RTC;
opts &= ~ICSNEOC2_OPEN_OPTIONS_GO_ONLINE;
if(icsneoc2_device_open(device, opts) != icsneoc2_error_success) {
icsneoc2_device_free(device);
continue;
}
bool supported = false;
icsneoc2_device_supports_gptp(device, &supported);
printf(" gPTP supported: %s\n", supported ? "yes" : "no");
if(supported) {
printf(" gPTP ports:\n");
print_gptp_ports(device);
}
icsneoc2_device_close(device);
icsneoc2_device_free(device);
}
return 0;
}
static void print_current_settings(icsneoc2_device_t* device) {
icsneoc2_gptp_profile_t profile = icsneoc2_gptp_profile_standard;
icsneoc2_gptp_role_t role = icsneoc2_gptp_role_disabled;
uint8_t port = 0;
bool clock_syntonization = false;
printf("\nCurrent gPTP settings:\n");
if(icsneoc2_settings_gptp_profile_get(device, &profile) == icsneoc2_error_success)
printf(" Profile: %s\n", gptp_profile_str(profile));
if(icsneoc2_settings_gptp_role_get(device, &role) == icsneoc2_error_success)
printf(" Role: %s\n", gptp_role_str(role));
if(icsneoc2_settings_gptp_enabled_port_get(device, &port) == icsneoc2_error_success)
printf(" Enabled port: %u%s\n", (unsigned)port, port == 0 ? " (disabled)" : "");
if(icsneoc2_settings_gptp_clock_syntonization_enabled_get(device, &clock_syntonization) == icsneoc2_error_success)
printf(" Clock syntonization: %s\n", clock_syntonization ? "enabled" : "disabled");
}
static long prompt_long(const char* prompt, long default_val, long min, long max) {
char buf[32] = {0};
printf("%s [%ld]: ", prompt, default_val);
fflush(stdout);
if(fgets(buf, sizeof(buf), stdin) == NULL || buf[0] == '\n')
return default_val;
char* end = NULL;
long val = strtol(buf, &end, 10);
if(end == buf || val < min || val > max) {
printf("Invalid input, using %ld.\n", default_val);
return default_val;
}
return val;
}
static int configure_device(icsneoc2_device_t* device) {
icsneoc2_error_t res;
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success)
return print_error_code("Failed to refresh settings", res);
print_current_settings(device);
printf("\nAvailable gPTP ports (0 = disabled):\n");
printf(" [0] Disabled\n");
print_gptp_ports(device);
printf("\nConfigure gPTP:\n");
long profile = prompt_long(" Profile (0=Standard, 1=Automotive)", 1, 0, 1);
res = icsneoc2_settings_gptp_profile_set(device, (icsneoc2_gptp_profile_t)profile);
if(res != icsneoc2_error_success)
return print_error_code("Failed to set profile", res);
long role = prompt_long(" Role (0=Disabled, 1=Passive, 2=Master, 3=Slave)", 3, 0, 3);
res = icsneoc2_settings_gptp_role_set(device, (icsneoc2_gptp_role_t)role);
if(res != icsneoc2_error_success)
return print_error_code("Failed to set role", res);
long port = prompt_long(" Enabled port index", 0, 0, 19);
res = icsneoc2_settings_gptp_enabled_port_set(device, (uint8_t)port);
if(res != icsneoc2_error_success)
return print_error_code("Failed to set enabled port", res);
long syntonization = prompt_long(" Clock syntonization (0=disabled, 1=enabled)", 0, 0, 1);
res = icsneoc2_settings_gptp_clock_syntonization_enabled_set(device, syntonization != 0);
if(res != icsneoc2_error_success)
return print_error_code("Failed to set clock syntonization", res);
printf("\nNote: icsneoc2_settings_apply() persists settings on the device.\n");
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success)
return print_error_code("Failed to apply settings", res);
printf("\nUpdated gPTP settings:\n");
print_current_settings(device);
return 0;
}
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);
icsneoc2_device_info_description_get(info, description, &description_len);
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 %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 supported = false;
icsneoc2_device_supports_gptp(device, &supported);
if(!supported) {
fprintf(stderr, "error: device does not support gPTP (%s)\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return 1;
}
int rc = configure_device(device);
printf("Closing %s\n", description);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
icsneoc2_enumeration_free(found_devices);
return rc;
}
+3
View File
@@ -86,6 +86,8 @@ void process_lin_messages(icsneoc2_message_t** messages, size_t count) {
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
icsneoc2_message_netid_get(messages[i], &netid); icsneoc2_message_netid_get(messages[i], &netid);
uint64_t timestamp = 0;
icsneoc2_message_timestamp_get(messages[i], &timestamp);
char netid_name[128] = {0}; char netid_name[128] = {0};
size_t netid_name_length = 128; size_t netid_name_length = 128;
icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
@@ -98,6 +100,7 @@ void process_lin_messages(icsneoc2_message_t** messages, size_t count) {
icsneoc2_message_lin_err_flags_get(messages[i], &err_flags); 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("\t%s RX | ID: 0x%02x | Protected ID: 0x%02x\n", netid_name, id, protected_id);
printf("\tTimestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
printf("\tData: ["); printf("\tData: [");
for(size_t x = 0; x < data_length; x++) { for(size_t x = 0; x < data_length; x++) {
printf(" 0x%02x", data[x]); printf(" 0x%02x", data[x]);
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-perf_test-example src/main.c)
target_link_libraries(libicsneoc2-perf_test-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-perf_test-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+137
View File
@@ -0,0 +1,137 @@
/*
* PerfTest setting example.
*
* Opens the first available device, enables the device-global PerfTest mode
* via icsneoc2_settings_perf_test_enabled_set(), reads messages for a few
* seconds while PerfTest is active, then disables PerfTest again. Each step
* reads the value back with icsneoc2_settings_perf_test_enabled_get() to
* confirm the change took effect.
*/
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2settings.h>
#include <icsneo/icsneoc2messages.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
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) {
fprintf(stderr, "%s: failed to get string for error code %u\n", message, error);
return (int)res;
}
fprintf(stderr, "%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
/* Sets PerfTest, applies it to the device, then reads it back to confirm. */
static icsneoc2_error_t set_and_verify_perf_test(icsneoc2_device_t* device, bool enable) {
icsneoc2_error_t res = icsneoc2_settings_perf_test_enabled_set(device, enable);
if(res != icsneoc2_error_success)
return res;
res = icsneoc2_settings_apply(device);
if(res != icsneoc2_error_success)
return res;
/* Re-read settings from the device so the read-back reflects what was
* actually persisted, not just the local settings buffer. */
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success)
return res;
bool value = !enable;
res = icsneoc2_settings_perf_test_enabled_get(device, &value);
if(res != icsneoc2_error_success)
return res;
printf("\tPerfTest now reads back as: %s\n", value ? "enabled" : "disabled");
if(value != enable) {
fprintf(stderr, "\tERROR: expected PerfTest %s but device reports %s\n",
enable ? "enabled" : "disabled", value ? "enabled" : "disabled");
return icsneoc2_error_get_settings_failure;
}
return icsneoc2_error_success;
}
/* Continuously drains and counts messages for the given wall-clock duration. */
static icsneoc2_error_t read_messages_for(icsneoc2_device_t* device, unsigned seconds) {
size_t total = 0;
printf("\tReading messages for %u seconds...\n", seconds);
time_t start = time(NULL);
while((time_t)(time(NULL) - start) < (time_t)seconds) {
/* Short timeout so an idle bus still lets us re-check the clock,
* while a flooding bus is drained as fast as messages arrive. */
icsneoc2_message_t* message = NULL;
icsneoc2_error_t res = icsneoc2_device_message_get(device, &message, 50);
if(res != icsneoc2_error_success)
return res;
if(message == NULL)
continue;
++total;
icsneoc2_message_free(message);
}
printf("\tReceived %zu messages in %u seconds.\n", total, seconds);
return icsneoc2_error_success;
}
int main(void) {
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 = 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);
/* Pull the current settings down from the device before reading/modifying them. */
res = icsneoc2_settings_refresh(device);
if(res != icsneoc2_error_success)
goto cleanup;
bool initial = false;
res = icsneoc2_settings_perf_test_enabled_get(device, &initial);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to read initial PerfTest state (device may not support it)", res);
goto cleanup;
}
printf("\tInitial PerfTest state: %s\n", initial ? "enabled" : "disabled");
printf("Enabling PerfTest...\n");
res = set_and_verify_perf_test(device, true);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to enable PerfTest", res);
goto cleanup;
}
res = read_messages_for(device, 3);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed while reading messages", res);
goto cleanup;
}
printf("Disabling PerfTest...\n");
res = set_and_verify_perf_test(device, false);
if(res != icsneoc2_error_success) {
print_error_code("\tFailed to disable PerfTest", res);
goto cleanup;
}
printf("PerfTest enable/read/disable cycle completed successfully.\n");
cleanup:
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return (int)res;
}
+14 -2
View File
@@ -176,6 +176,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
// Print the type and bus type of each message // Print the type and bus type of each message
size_t tx_count = 0; size_t tx_count = 0;
size_t can_error_count = 0; size_t can_error_count = 0;
size_t internal_count = 0;
icsneoc2_error_t res = icsneoc2_error_success; icsneoc2_error_t res = icsneoc2_error_success;
for(size_t i = 0; i < messages_count; i++) { for(size_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i]; icsneoc2_message_t* message = messages[i];
@@ -216,13 +217,21 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
continue; continue;
} }
// This example only cares about bus traffic, so skip internal
// device/status messages.
icsneoc2_network_type_t internal_check = icsneoc2_network_type_invalid;
res = icsneoc2_message_network_type_get(message, &internal_check);
if(res == icsneoc2_error_success && internal_check == icsneoc2_network_type_internal) {
internal_count++;
continue;
}
bool is_frame = false; bool is_frame = false;
res = icsneoc2_message_is_frame(message, &is_frame); res = icsneoc2_message_is_frame(message, &is_frame);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a frame", res); return print_error_code("\tFailed to check if message is a frame", res);
} }
if(!is_frame) { if(!is_frame) {
printf("Ignoring non-frame message at index %zu\n", i);
continue; continue;
} }
icsneoc2_network_type_t network_type; icsneoc2_network_type_t network_type;
@@ -244,6 +253,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type); printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type);
if(network_type == icsneoc2_network_type_can) { if(network_type == icsneoc2_network_type_can) {
uint64_t timestamp = 0;
uint64_t arbid = 0; uint64_t arbid = 0;
int32_t dlc = 0; int32_t dlc = 0;
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
@@ -256,6 +266,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
bool is_tx = false; bool is_tx = false;
icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid); icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_timestamp_get(message, &timestamp);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags); result += icsneoc2_message_can_props_get(message, &arbid, &can_flags);
result += icsneoc2_message_data_get(message, data, &data_length); result += icsneoc2_message_data_get(message, data, &data_length);
result += icsneoc2_message_is_transmit(message, &is_tx); result += icsneoc2_message_is_transmit(message, &is_tx);
@@ -276,6 +287,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
dlc = (int32_t)data_length; dlc = (int32_t)data_length;
printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : ""); printf("\t %s%s\n", is_tx ? "TX" : "RX", is_error ? " [Error]" : "");
printf("\t Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
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 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", printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "", is_remote ? " RTR" : "",
@@ -293,7 +305,7 @@ int process_message(icsneoc2_message_t** messages, size_t messages_count) {
printf(" ]\n"); printf(" ]\n");
} }
} }
printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count); printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors, %zu internal (skipped)\n", messages_count, tx_count, can_error_count, internal_count);
return icsneoc2_error_success; return icsneoc2_error_success;
} }
+36 -2
View File
@@ -359,6 +359,8 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
// Print the type and bus type of each message // Print the type and bus type of each message
size_t tx_count = 0; size_t tx_count = 0;
size_t can_error_count = 0; size_t can_error_count = 0;
size_t app_error_count = 0;
size_t internal_count = 0;
for(size_t i = 0; i < messages_count; i++) { for(size_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i]; icsneoc2_message_t* message = messages[i];
@@ -392,13 +394,42 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
continue; continue;
} }
// Check for application error messages
bool is_app_error = false;
res = icsneoc2_message_is_app_error(message, &is_app_error);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is an app error", res);
}
if(is_app_error) {
icsneoc2_app_error_type_t error_type = icsneoc2_app_error_type_no_error;
icsneoc2_netid_t error_netid = 0;
char description[256] = {0};
size_t description_length = sizeof(description);
res = icsneoc2_message_app_error_props_get(message, &error_type, &error_netid);
res += icsneoc2_message_app_error_string_get(message, description, &description_length);
if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to get app error properties", res);
}
printf("\t%zd) App Error (type %u) on netid 0x%x: %s\n", i, error_type, error_netid, description);
app_error_count++;
continue;
}
// This example only cares about bus traffic, so skip internal
// device/status messages.
icsneoc2_network_type_t internal_check = icsneoc2_network_type_invalid;
res = icsneoc2_message_network_type_get(message, &internal_check);
if(res == icsneoc2_error_success && internal_check == icsneoc2_network_type_internal) {
internal_count++;
continue;
}
bool is_frame = false; bool is_frame = false;
res = icsneoc2_message_is_frame(message, &is_frame); res = icsneoc2_message_is_frame(message, &is_frame);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {
return print_error_code("\tFailed to check if message is a frame", res); return print_error_code("\tFailed to check if message is a frame", res);
} }
if(!is_frame) { if(!is_frame) {
printf("Ignoring non-frame message at index %zu\n", i);
continue; continue;
} }
icsneoc2_network_type_t network_type; icsneoc2_network_type_t network_type;
@@ -426,6 +457,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type); printf("\t%zd) network type: %s (%u)\n", i, network_type_name, network_type);
if(network_type == icsneoc2_network_type_can) { if(network_type == icsneoc2_network_type_can) {
uint64_t timestamp = 0;
uint64_t arbid = 0; uint64_t arbid = 0;
int32_t dlc = 0; int32_t dlc = 0;
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
@@ -436,6 +468,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
size_t netid_name_length = 128; size_t netid_name_length = 128;
icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid); icsneoc2_error_t result = icsneoc2_message_netid_get(message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length); result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_timestamp_get(message, &timestamp);
result += icsneoc2_message_can_props_get(message, &arbid, &can_flags); result += icsneoc2_message_can_props_get(message, &arbid, &can_flags);
result += icsneoc2_message_data_get(message, data, &data_length); result += icsneoc2_message_data_get(message, data, &data_length);
if(result != icsneoc2_error_success) { if(result != icsneoc2_error_success) {
@@ -452,6 +485,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0; bool tx_error = (can_flags & ICSNEOC2_MESSAGE_CAN_FLAGS_TX_ERROR) != 0;
dlc = (int32_t)data_length; dlc = (int32_t)data_length;
printf("\t Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
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 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", printf("\t Flags:%s%s%s%s%s%s%s%s\n",
is_remote ? " RTR" : "", is_remote ? " RTR" : "",
@@ -469,7 +503,7 @@ int process_messages(icsneoc2_message_t** messages, size_t messages_count) {
printf(" ]\n"); printf(" ]\n");
} }
} }
printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors\n", messages_count, tx_count, can_error_count); printf("\tReceived %zu messages total, %zu were TX messages, %zu were CAN errors, %zu were app errors, %zu internal (skipped)\n", messages_count, tx_count, can_error_count, app_error_count, internal_count);
return icsneoc2_error_success; return icsneoc2_error_success;
} }
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-supported-devices-example src/main.c)
target_link_libraries(libicsneoc2-supported-devices-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-supported-devices-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+55
View File
@@ -0,0 +1,55 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
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\n", message, error);
return (int)res;
}
printf("%s: %s (%u)\n", message, error_str, error);
return (int)error;
}
int main(void) {
icsneoc2_supported_device_t* supported_devices = NULL;
icsneoc2_error_t res = icsneoc2_supported_devices_enumerate(&supported_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to enumerate supported devices", res);
}
if(!supported_devices) {
printf("No supported devices found.\n");
return 0;
}
printf("Supported devices:\n");
for(icsneoc2_supported_device_t* cur = supported_devices; cur != NULL; cur = icsneoc2_supported_devices_next(cur)) {
icsneoc2_devicetype_t device_type = 0;
res = icsneoc2_supported_device_get(cur, &device_type);
if(res != icsneoc2_error_success) {
icsneoc2_supported_devices_free(supported_devices);
return print_error_code("Failed to get supported device type", res);
}
char name[128] = {0};
size_t name_len = sizeof(name);
res = icsneoc2_device_type_name_get(device_type, name, &name_len);
if(res != icsneoc2_error_success) {
icsneoc2_supported_devices_free(supported_devices);
return print_error_code("Failed to get supported device type name", res);
}
printf(" %s (%u)\n", name, (unsigned int)device_type);
}
res = icsneoc2_supported_devices_free(supported_devices);
if(res != icsneoc2_error_success) {
return print_error_code("Failed to free supported device list", res);
}
return 0;
}
+5 -1
View File
@@ -468,6 +468,7 @@ static int message_matches_loopback_frame(icsneoc2_message_t* message, const uin
static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label) { static int print_ethernet_message(icsneoc2_message_t* message, const char* direction_label) {
icsneoc2_netid_t netid = 0; icsneoc2_netid_t netid = 0;
uint64_t timestamp = 0;
char netid_name[64] = {0}; char netid_name[64] = {0};
uint8_t dst_mac[6] = {0}; uint8_t dst_mac[6] = {0};
uint8_t src_mac[6] = {0}; uint8_t src_mac[6] = {0};
@@ -483,11 +484,14 @@ static int print_ethernet_message(icsneoc2_message_t* message, const char* direc
res = icsneoc2_message_netid_get(message, &netid); res = icsneoc2_message_netid_get(message, &netid);
if(res != icsneoc2_error_success) return print_error_code("Failed to get message netid", res); 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; if(get_netid_name(netid, netid_name, sizeof(netid_name)) != 0) return 1;
res = icsneoc2_message_timestamp_get(message, &timestamp);
if(res != icsneoc2_error_success) return print_error_code("Failed to get message timestamp", res);
res = icsneoc2_message_data_get(message, data, &data_length); res = icsneoc2_message_data_get(message, data, &data_length);
if(res != icsneoc2_error_success) return print_error_code("Failed to get Ethernet data", res); 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); printf("%s on %s: %zu bytes\n", direction_label, netid_name, data_length);
printf(" Timestamp: %" PRIu64 " ns since 2007-01-01 UTC\n", timestamp);
res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac); res = icsneoc2_message_eth_mac_get(message, dst_mac, src_mac);
if(res == icsneoc2_error_success) { if(res == icsneoc2_error_success) {
@@ -640,4 +644,4 @@ static int poll_for_loopback_messages(icsneoc2_device_t* device,
printf("Loopback complete: TX echo on %s and RX frame on %s were both observed.\n", tx_name, rx_name); printf("Loopback complete: TX echo on %s and RX frame on %s were both observed.\n", tx_name, rx_name);
return 0; return 0;
} }
+6
View File
@@ -0,0 +1,6 @@
add_executable(libicsneoc2-termination-example src/main.c)
target_link_libraries(libicsneoc2-termination-example icsneoc2-static)
if(WIN32)
target_compile_definitions(libicsneoc2-termination-example PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
+91
View File
@@ -0,0 +1,91 @@
#include <icsneo/icsneoc2.h>
#include <icsneo/icsneoc2messages.h>
#include <icsneo/icsneoc2settings.h>
#include <stdio.h>
#include <stdlib.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 %u with error code %u\n", message, error, res);
return (int)res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
int main() {
icsneoc2_error_t res;
icsneoc2_device_t* device = NULL;
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);
}
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);
size_t count = 0;
icsneoc2_termination_group_t* groups = NULL;
res = icsneoc2_settings_termination_groups_enumerate(device, &groups, &count);
if(res != icsneoc2_error_success) {
print_error_code("Failed to enumerate termination groups", res);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 1;
}
if(count == 0) {
printf("This device does not support software switchable termination.\n");
} else {
printf("Found %zu termination group(s) (only one network per group may be terminated at a time):\n", count);
}
size_t group_index = 0;
for(icsneoc2_termination_group_t* group = groups; group; group = icsneoc2_termination_group_next(group), group_index++) {
// First call with a NULL buffer to learn how many networks are in this group.
size_t network_count = 0;
icsneoc2_termination_group_networks_get(group, NULL, &network_count);
icsneoc2_netid_t* netids = (icsneoc2_netid_t*)malloc(network_count * sizeof(icsneoc2_netid_t));
if(!netids) {
print_error_code("Out of memory", icsneoc2_error_out_of_memory);
break;
}
// Second call to fill the buffer.
res = icsneoc2_termination_group_networks_get(group, netids, &network_count);
if(res != icsneoc2_error_success) {
print_error_code("Failed to get termination group networks", res);
free(netids);
continue;
}
printf(" Group %zu:", group_index);
for(size_t i = 0; i < network_count; i++) {
char name[64] = {0};
size_t name_length = sizeof(name);
if(icsneoc2_netid_name_get(netids[i], name, &name_length) == icsneoc2_error_success) {
printf(" %s", name);
} else {
printf(" %u", netids[i]);
}
if(i + 1 < network_count) {
printf(",");
}
}
printf("\n");
free(netids);
}
icsneoc2_settings_termination_groups_free(groups);
icsneoc2_device_close(device);
icsneoc2_device_free(device);
return 0;
}
+3
View File
@@ -406,6 +406,9 @@ int main(int argc, char** argv) {
if(it == devices.end()) { if(it == devices.end()) {
std::cerr << "Could not find RAD-A2B." << std::endl; std::cerr << "Could not find RAD-A2B." << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -92,6 +92,9 @@ int main(int argc, const char** argv) {
if(!device) { if(!device) {
std::cerr << "Device with serial " << serial << " not found" << std::endl; std::cerr << "Device with serial " << serial << " not found" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1; return -1;
} }
} else { } else {
@@ -99,6 +102,9 @@ int main(int argc, const char** argv) {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.empty()) { if(devices.empty()) {
std::cerr << "No devices found" << std::endl; std::cerr << "No devices found" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1; return -1;
} }
device = devices[0]; device = devices[0];
@@ -9,7 +9,7 @@
/* /*
* App errors are responses from the device indicating internal runtime errors * App errors are responses from the device indicating internal runtime errors
* NOTE: To trigger the app error in this example, disable the DW CAN 01 network on the device * NOTE: To trigger the app error in this example, disable the DW CAN 01 network on the device
* (e.g. with neoVI Explorer) * (e.g. with ICS Device Manager)
*/ */
int main() { int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl; std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
@@ -17,6 +17,13 @@ int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+3
View File
@@ -33,6 +33,9 @@ int main(int argc, char** argv) {
if(it == devices.end()) { if(it == devices.end()) {
std::cout << "Failed to find device." << std::endl; std::cout << "Failed to find device." << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-device-info-example src/DeviceInfoExample.cpp)
target_link_libraries(libicsneocpp-device-info-example icsneocpp)
@@ -0,0 +1,80 @@
#include <iostream>
#include <iomanip>
#include <sstream>
#include "icsneo/icsneocpp.h"
static std::string formatMAC(const std::array<uint8_t, icsneo::MACAddressLength> addr) {
std::ostringstream oss;
for(size_t i = 0; i < icsneo::MACAddressLength; i++) {
if(i > 0) {
oss << ':';
}
oss << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast<unsigned>(addr[i]);
}
return oss.str();
}
int main() {
// ===== Device Selection =====
std::cout << "Searching for devices...\n";
auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
std::cout << "No devices found.\n";
return 1;
}
for(size_t i = 0; i < devices.size(); i++) {
std::cout << " [" << (i + 1) << "] " << devices[i]->describe() << "\n";
}
int choice;
std::cout << "Select device (1-" << devices.size() << "): ";
if(!(std::cin >> choice) || choice < 1 || choice > (int)devices.size()) {
std::cout << "Invalid selection.\n";
return 1;
}
auto& device = devices[choice - 1];
std::cout << "\nOpening " << device->describe() << "... ";
if(!device->open()) {
std::cout << "FAIL\n" << icsneo::GetLastError() << "\n";
return 1;
}
std::cout << "OK\n\n";
// ===== Serial Number =====
std::cout << "Serial: " << device->getSerial() << "\n";
// ===== PCB Serial Number =====
auto pcbSerial = device->getPCBSerial();
if(pcbSerial.has_value()) {
std::cout << "PCB Serial: ";
for(auto b : *pcbSerial)
std::cout << (char)b;
std::cout << "\n";
} else {
std::cout << "PCB Serial: Not supported\n";
}
auto macs = device->getMACAddresses();
if(!macs.empty()) {
std::cout << "MACs: " << macs.size()
<< (macs.size() == 1 ? " entry" : " entries") << "\n";
for(auto macPair : macs) {
std::cout << " " << std::left << std::setw(20)
<< icsneo::Network::GetNetIDString(static_cast<icsneo::Network::NetID>(macPair.first))
<< " " << formatMAC(macPair.second) << "\n";
}
} else {
std::cout << "MACs: Not supported\n";
}
// ===== Cleanup =====
std::cout << "\nClosing device... ";
std::cout << (device->close() ? "OK" : "FAIL") << "\n";
return 0;
}
@@ -12,7 +12,9 @@ int main() {
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) { if(devices.empty()) {
std::cout << "error: no devices found" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1; return -1;
} }
@@ -138,6 +138,12 @@ std::vector<std::shared_ptr<icsneo::FlexRayMessage>> makeDummyFlexRayMessages(si
int main() { int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return -1;
}
std::shared_ptr<icsneo::Device> flexrayDevice = nullptr; std::shared_ptr<icsneo::Device> flexrayDevice = nullptr;
for (auto&& device : devices) { for (auto&& device : devices) {
if (device->getExtension("FlexRay")) { if (device->getExtension("FlexRay")) {
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-gptp-settings src/GPTPSettingsExample.cpp)
target_link_libraries(libicsneocpp-gptp-settings icsneocpp)
@@ -0,0 +1,179 @@
#include <iostream>
#include <iomanip>
#include <vector>
#include <optional>
#include <string>
#include <limits>
#include "icsneo/icsneocpp.h"
/* Maps a Network::NetID to its gPTP port index (0 = not a gPTP port). */
static uint8_t netidToGPTPPort(icsneo::Network::NetID netid) {
using N = icsneo::Network::NetID;
switch(netid) {
case N::AE_01: return 1;
case N::AE_02: return 2;
case N::AE_03: return 3;
case N::AE_04: return 4;
case N::AE_05: return 5;
case N::AE_06: return 6;
case N::AE_07: return 7;
case N::AE_08: return 8;
case N::AE_09: return 9;
case N::AE_10: return 10;
case N::AE_11: return 11;
case N::AE_12: return 12;
case N::ETHERNET_01: return 13;
case N::ETHERNET_02: return 14;
case N::ETHERNET_03: return 15;
case N::AE_13: return 16;
case N::AE_14: return 17;
case N::AE_15: return 18;
case N::AE_16: return 19;
default: return 0;
}
}
static std::string gptpProfileStr(RADGPTPProfile p) {
switch(p) {
case RAD_GPTP_PROFILE_STANDARD: return "Standard";
case RAD_GPTP_PROFILE_AUTOMOTIVE: return "Automotive";
default: return "Unknown";
}
}
static std::string gptpRoleStr(RADGPTPRole r) {
switch(r) {
case RAD_GPTP_ROLE_DISABLED: return "Disabled";
case RAD_GPTP_ROLE_PASSIVE: return "Passive";
case RAD_GPTP_ROLE_MASTER: return "Master";
case RAD_GPTP_ROLE_SLAVE: return "Slave";
default: return "Unknown";
}
}
template<typename T>
static std::string optStr(const std::optional<T>& opt) {
if(!opt.has_value()) return "N/A";
if constexpr(std::is_same_v<T, bool>)
return opt.value() ? "enabled" : "disabled";
else
return std::to_string(static_cast<int>(opt.value()));
}
static long promptLong(const std::string& prompt, long defaultVal, long min, long max) {
std::cout << prompt << " [" << defaultVal << "]: " << std::flush;
std::string input;
std::getline(std::cin, input);
if(input.empty())
return defaultVal;
try {
long val = std::stol(input);
if(val >= min && val <= max)
return val;
} catch(...) {}
std::cout << "Invalid input, using " << defaultVal << ".\n";
return defaultVal;
}
static void printGPTPPorts(const std::shared_ptr<icsneo::Device>& device) {
for(const auto& net : device->getSupportedTXNetworks()) {
uint8_t port = netidToGPTPPort(net.getNetID());
if(port == 0) continue;
std::cout << " [" << (int)port << "] " << net << "\n";
}
}
static void printCurrentSettings(const std::shared_ptr<icsneo::Device>& device) {
std::cout << "\nCurrent gPTP settings:\n";
auto profile = device->settings->getGPTPProfile();
auto role = device->settings->getGPTPRole();
auto port = device->settings->getGPTPEnabledPort();
auto synton = device->settings->isGPTPClockSyntonizationEnabled();
if(profile.has_value())
std::cout << " Profile: " << gptpProfileStr(profile.value()) << "\n";
if(role.has_value())
std::cout << " Role: " << gptpRoleStr(role.value()) << "\n";
if(port.has_value())
std::cout << " Enabled port: " << (int)port.value() << (port.value() == 0 ? " (disabled)" : "") << "\n";
if(synton.has_value())
std::cout << " Clock syntonization: " << optStr(synton) << "\n";
}
int main() {
std::cout << "Finding devices... " << std::flush;
auto devices = icsneo::FindAllDevices();
std::cout << devices.size() << " found\n";
if(devices.empty()) {
auto err = icsneo::GetLastError();
if(err.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << err << "\n";
return 1;
}
std::vector<std::shared_ptr<icsneo::Device>> gptp_devices;
for(auto& d : devices) {
if(d->supportsGPTP())
gptp_devices.push_back(d);
}
if(gptp_devices.empty()) {
std::cout << "No gPTP-capable devices found.\n";
return 1;
}
std::cout << "\nAvailable gPTP-capable devices:\n";
for(size_t i = 0; i < gptp_devices.size(); ++i)
std::cout << " [" << (i + 1) << "] " << gptp_devices[i]->describe() << "\n";
long choice = promptLong("Select device", 1, 1, (long)gptp_devices.size());
auto device = gptp_devices[choice - 1];
std::cout << "\nOpening " << device->describe() << "... " << std::flush;
if(!device->open()) {
std::cout << "failed\n" << icsneo::GetLastError() << "\n";
return 1;
}
std::cout << "OK\n";
if(!device->settings->refresh()) {
std::cout << "Failed to refresh settings\n";
device->close();
return 1;
}
printCurrentSettings(device);
std::cout << "\nAvailable gPTP ports (0 = disabled):\n";
std::cout << " [0] Disabled\n";
printGPTPPorts(device);
std::cout << "\nConfigure gPTP:\n";
long profile = promptLong(" Profile (0=Standard, 1=Automotive)", 1, 0, 1);
device->settings->setGPTPProfile(static_cast<RADGPTPProfile>(profile));
long role = promptLong(" Role (0=Disabled, 1=Passive, 2=Master, 3=Slave)", 3, 0, 3);
device->settings->setGPTPRole(static_cast<RADGPTPRole>(role));
long port = promptLong(" Enabled port index", 0, 0, 19);
device->settings->setGPTPEnabledPort(static_cast<uint8_t>(port));
long syntonization = promptLong(" Clock syntonization (0=disabled, 1=enabled)", 0, 0, 1);
device->settings->setGPTPClockSyntonizationEnabled(syntonization != 0);
long permanent = promptLong("\nSave to EEPROM? (0=temporary, 1=permanent)", 0, 0, 1);
if(!device->settings->apply(permanent == 0)) {
std::cout << "Failed to apply settings\n" << icsneo::GetLastError() << "\n";
device->close();
return 1;
}
printCurrentSettings(device);
std::cout << "\nClosing " << device->describe() << "\n";
device->close();
return 0;
}
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-iso15765-loopback src/ISO15765Loopback.cpp)
target_link_libraries(libicsneocpp-iso15765-loopback icsneocpp)
@@ -0,0 +1,450 @@
#include <cctype>
#include <chrono>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>
#include "icsneo/icsneocpp.h"
namespace {
using namespace std::chrono_literals;
enum class Mode {
None,
Raw,
SingleFrame,
Both,
};
struct Options {
Mode mode = Mode::None;
std::string testerSerial;
std::string ecuSerial;
int64_t baud = 500000;
bool keepBaud = false;
uint32_t txId = 0x7E0;
uint32_t fcId = 0x7E8;
std::optional<size_t> payloadBytes;
int listenMs = 2000;
uint8_t padding = 0x00;
uint16_t fsTimeoutMs = 75;
uint16_t fsWaitMs = 150;
uint16_t cfTimeoutMs = 150;
};
std::mutex gLogMutex;
void logLine(const std::string& line) {
std::lock_guard<std::mutex> lk(gLogMutex);
std::cout << line << std::endl;
}
bool iequals(const std::string& a, const std::string& b) {
if(a.size() != b.size())
return false;
for(size_t i = 0; i < a.size(); i++) {
if(std::tolower(static_cast<unsigned char>(a[i])) != std::tolower(static_cast<unsigned char>(b[i])))
return false;
}
return true;
}
std::string hexBytes(const std::vector<uint8_t>& data) {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for(size_t i = 0; i < data.size(); i++) {
if(i)
oss << ' ';
oss << std::setw(2) << static_cast<unsigned>(data[i]);
}
return oss.str();
}
std::string pciDescribe(const std::vector<uint8_t>& data) {
if(data.empty())
return {};
const uint8_t pciType = static_cast<uint8_t>(data[0] >> 4);
const uint8_t pciLow = static_cast<uint8_t>(data[0] & 0x0F);
std::ostringstream oss;
switch(pciType) {
case 0x0:
if(pciLow > 7 || data.size() < static_cast<size_t>(1 + pciLow))
return {};
oss << "SF len=" << static_cast<unsigned>(pciLow);
break;
case 0x1: {
if(data.size() < 8)
return {};
const uint16_t len = static_cast<uint16_t>((pciLow << 8) | data[1]);
if(len < 8)
return {};
oss << "FF len=" << len;
break;
}
case 0x2:
if(data.size() < 2)
return {};
oss << "CF SN=" << static_cast<unsigned>(pciLow);
break;
case 0x3: {
if(data.size() < 3 || pciLow > 2)
return {};
static const char* fsName[] = { "CTS", "WAIT", "OVFLW" };
oss << "FC FS=" << fsName[pciLow];
oss << " BS=" << static_cast<unsigned>(data[1]);
oss << " STmin=0x" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<unsigned>(data[2]);
break;
}
default:
return {};
}
return oss.str();
}
void printUsage(const char* argv0) {
std::cerr
<< "Usage: " << argv0 << " --raw|--sf|--both [options]\n\n"
<< "Two Intrepid devices with CAN1 wired together (CANH/CANL, terminated).\n"
<< "Prints CAN1 frames with ISO-TP PCI decode (SF/FF/CF/FC).\n\n"
<< "Modes:\n"
<< " --raw Raw CAN ping-pong (cable check)\n"
<< " --sf Firmware ISO-TP single-frame TX from tester\n"
<< " --both Firmware ISO-TP TX on tester, firmware flow-control on ECU\n\n"
<< "Devices:\n"
<< " --tester SERIAL Tester (sender) serial\n"
<< " --ecu SERIAL ECU / peer serial\n"
<< " Optional if exactly two devices are found.\n\n"
<< "Optional:\n"
<< " --baud N CAN1 baud (default 500000, applied temporarily)\n"
<< " --keep-baud Do not change device baud\n"
<< " --tx-id HEX Tester ISO-TP CAN ID (default 0x7E0)\n"
<< " --fc-id HEX Flow-control CAN ID (default 0x7E8)\n"
<< " --bytes N ISO-TP payload size (sf default 5, both default 20)\n"
<< " --listen-ms N Time to listen after the action (default 2000)\n";
}
uint32_t parseU32(const std::string& s) {
return static_cast<uint32_t>(std::stoul(s, nullptr, 0));
}
bool parseArgs(int argc, char** argv, Options& opt) {
for(int i = 1; i < argc; i++) {
const std::string a = argv[i];
auto need = [&](const char* name) -> std::string {
if(i + 1 >= argc)
throw std::runtime_error(std::string("missing value for ") + name);
return argv[++i];
};
if(a == "--raw")
opt.mode = Mode::Raw;
else if(a == "--sf")
opt.mode = Mode::SingleFrame;
else if(a == "--both")
opt.mode = Mode::Both;
else if(a == "--tester")
opt.testerSerial = need("--tester");
else if(a == "--ecu")
opt.ecuSerial = need("--ecu");
else if(a == "--baud")
opt.baud = static_cast<int64_t>(std::stoll(need("--baud")));
else if(a == "--keep-baud")
opt.keepBaud = true;
else if(a == "--tx-id")
opt.txId = parseU32(need("--tx-id"));
else if(a == "--fc-id")
opt.fcId = parseU32(need("--fc-id"));
else if(a == "--bytes")
opt.payloadBytes = static_cast<size_t>(std::stoul(need("--bytes")));
else if(a == "--listen-ms")
opt.listenMs = std::stoi(need("--listen-ms"));
else if(a == "-h" || a == "--help") {
printUsage(argv[0]);
return false;
} else {
std::cerr << "Unknown argument: " << a << "\n";
printUsage(argv[0]);
return false;
}
}
if(opt.mode == Mode::None) {
printUsage(argv[0]);
return false;
}
return true;
}
size_t defaultPayloadSize(Mode mode) {
return mode == Mode::SingleFrame ? 5 : 20;
}
std::vector<uint8_t> makePayload(size_t n) {
std::vector<uint8_t> data(n);
for(size_t i = 0; i < n; i++)
data[i] = static_cast<uint8_t>(i & 0xFF);
return data;
}
bool isExtended(uint32_t id) {
return id > 0x7FFu;
}
void printApiResult(const char* what, bool ok) {
std::ostringstream oss;
oss << " " << what << ": " << (ok ? "OK" : "FAIL");
if(!ok) {
const auto err = icsneo::GetLastError();
if(err.getType() != icsneo::APIEvent::Type::NoErrorFound)
oss << " [" << err << "]";
}
logLine(oss.str());
}
bool transmitCan(icsneo::Device& device, uint32_t arbId, std::vector<uint8_t> data) {
auto frame = std::make_shared<icsneo::CANMessage>();
frame->network = icsneo::Network::NetID::DWCAN_01;
frame->arbid = arbId;
frame->data = std::move(data);
frame->isExtended = isExtended(arbId);
frame->isCANFD = false;
const bool ok = device.transmit(frame);
if(!ok)
printApiResult("transmit CAN", ok);
return ok;
}
void fillIso15765(icsneo::Iso15765MessageArgs& msg, const Options& opt, const std::vector<uint8_t>& payload, bool rx) {
msg.setTxIndex(0);
msg.setArbId(icsneo::Iso15765MessageArgs::ArbId(opt.txId, isExtended(opt.txId)));
msg.setFlowControlArbId(icsneo::Iso15765MessageArgs::ArbId(opt.fcId, isExtended(opt.fcId)));
msg.setFlowControlArbIdMask(isExtended(opt.txId) ? 0x1FFFFFFFu : 0x7FFu);
msg.setIsCanFd(false);
msg.setIsBrsEnabled(false);
msg.setTxDl(8);
msg.setPaddingValue(opt.padding);
msg.setFsTimeout(opt.fsTimeoutMs);
msg.setFsWaitTimeout(opt.fsWaitMs);
msg.setCfTimeout(opt.cfTimeoutMs);
msg.setIsFlowControlEnabled(rx);
if(!payload.empty()) {
auto copy = payload;
msg.setData(std::move(copy));
}
}
struct Sniffer {
const char* tag = "";
std::optional<uint64_t> t0;
std::mutex t0Mutex;
void onCan(const std::shared_ptr<icsneo::CANMessage>& can) {
{
std::lock_guard<std::mutex> lk(t0Mutex);
if(!t0)
t0 = can->timestamp;
}
double relMs = 0.0;
{
std::lock_guard<std::mutex> lk(t0Mutex);
if(t0 && can->timestamp >= *t0)
relMs = static_cast<double>(can->timestamp - *t0) / 1e6;
}
std::ostringstream oss;
oss << " [" << tag << (can->transmitted ? " TX" : " RX") << "] "
<< std::fixed << std::setprecision(3) << relMs << " ms "
<< can->network << " 0x" << std::hex << std::uppercase
<< std::setw(isExtended(can->arbid) ? 8 : 3) << std::setfill('0') << can->arbid
<< std::dec << " [" << can->data.size() << "] " << hexBytes(can->data);
const auto pci = pciDescribe(can->data);
if(!pci.empty())
oss << " " << pci;
logLine(oss.str());
}
};
void addCanSniffer(icsneo::Device& device, Sniffer& sniffer) {
auto filter = std::make_shared<icsneo::MessageFilter>(icsneo::Network::NetID::DWCAN_01);
device.addMessageCallback(std::make_shared<icsneo::MessageCallback>(filter, [&sniffer](std::shared_ptr<icsneo::Message> message) {
if(message->type != icsneo::Message::Type::Frame)
return;
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
if(frame->network.getType() != icsneo::Network::Type::CAN)
return;
sniffer.onCan(std::static_pointer_cast<icsneo::CANMessage>(message));
}));
}
bool openAndOnline(std::shared_ptr<icsneo::Device>& device, const Options& opt) {
logLine(std::string("Opening ") + device->describe() + " ...");
if(!device->open()) {
printApiResult("open", false);
return false;
}
if(!opt.keepBaud && device->settings) {
if(!device->settings->setBaudrateFor(icsneo::Network::NetID::DWCAN_01, opt.baud))
printApiResult("setBaudrateFor", false);
else if(!device->settings->apply(true))
printApiResult("settings->apply(temporary)", false);
}
if(!device->goOnline()) {
printApiResult("goOnline", false);
device->close();
return false;
}
return true;
}
void closeDevice(const std::shared_ptr<icsneo::Device>& device) {
if(!device)
return;
device->iso15765DisableAll();
if(device->isOnline())
device->goOffline();
if(device->isOpen())
device->close();
}
bool enableIso(icsneo::Device& device, const char* who) {
const bool ok = device.iso15765Enable(icsneo::Network(icsneo::Network::NetID::DWCAN_01));
printApiResult((std::string(who) + " ISO15765_Enable").c_str(), ok);
return ok;
}
bool receiveIso(icsneo::Device& device, const Options& opt) {
icsneo::Iso15765MessageArgs msg;
fillIso15765(msg, opt, {}, true);
const bool ok = device.iso15765SetupRxFlowControl(icsneo::Network(icsneo::Network::NetID::DWCAN_01), msg);
printApiResult("ECU ISO15765_ReceiveMessage", ok);
return ok;
}
bool transmitIso(icsneo::Device& device, const Options& opt, const std::vector<uint8_t>& payload) {
icsneo::Iso15765MessageArgs msg;
fillIso15765(msg, opt, payload, false);
const bool ok = device.iso15765TransmitMessage(
icsneo::Network(icsneo::Network::NetID::DWCAN_01), msg, std::chrono::milliseconds(0));
printApiResult("tester ISO15765_TransmitMessage", ok);
return ok;
}
std::shared_ptr<icsneo::Device> findBySerial(const std::vector<std::shared_ptr<icsneo::Device>>& devices, const std::string& serial) {
for(const auto& d : devices) {
if(iequals(d->getSerial(), serial))
return d;
}
return nullptr;
}
} // namespace
int main(int argc, char** argv) {
Options opt;
try {
if(!parseArgs(argc, argv, opt))
return 1;
} catch(const std::exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
}
std::cout << "libicsneo " << icsneo::GetVersion() << std::endl;
auto devices = icsneo::FindAllDevices();
std::cout << "Found " << devices.size() << " device(s)\n";
for(const auto& d : devices)
std::cout << " " << d->describe() << " serial=" << d->getSerial() << "\n";
if(devices.size() < 2) {
std::cerr << "Need two devices connected.\n";
return 1;
}
std::shared_ptr<icsneo::Device> tester;
std::shared_ptr<icsneo::Device> ecu;
if(opt.testerSerial.empty() && opt.ecuSerial.empty()) {
if(devices.size() != 2) {
std::cerr << "More than two devices found; pass --tester and --ecu serials.\n";
return 1;
}
tester = devices[0];
ecu = devices[1];
std::cout << "No serials given; using first as tester, second as ECU.\n";
} else {
if(opt.testerSerial.empty() || opt.ecuSerial.empty()) {
std::cerr << "Pass both --tester and --ecu, or neither.\n";
return 1;
}
tester = findBySerial(devices, opt.testerSerial);
ecu = findBySerial(devices, opt.ecuSerial);
if(!tester || !ecu) {
std::cerr << "Could not match tester/ECU serials.\n";
return 1;
}
}
const size_t payloadSize = opt.payloadBytes.value_or(defaultPayloadSize(opt.mode));
const auto payload = makePayload(payloadSize);
std::cout << "Tester: " << tester->describe() << "\n"
<< "ECU: " << ecu->describe() << "\n";
if(opt.mode != Mode::Raw) {
std::ostringstream hdr;
hdr << "CAN1 TX 0x" << std::hex << std::uppercase << opt.txId
<< " FC 0x" << opt.fcId << std::dec
<< " payload " << payloadSize << " bytes";
std::cout << hdr.str() << "\n";
}
std::cout << std::endl;
if(!openAndOnline(tester, opt) || !openAndOnline(ecu, opt))
return 1;
Sniffer testerSniff;
testerSniff.tag = "TESTER";
Sniffer ecuSniff;
ecuSniff.tag = "ECU ";
addCanSniffer(*tester, testerSniff);
addCanSniffer(*ecu, ecuSniff);
switch(opt.mode) {
case Mode::Raw:
logLine("Mode --raw: tester 0x123, then ECU 0x456");
transmitCan(*tester, 0x123, { 0x11, 0x22, 0x33, 0x44 });
std::this_thread::sleep_for(200ms);
transmitCan(*ecu, 0x456, { 0x55, 0x66, 0x77, 0x88 });
break;
case Mode::SingleFrame:
logLine("Mode --sf: firmware ISO-TP single frame from tester");
if(payload.size() > 7)
logLine(" warning: payload > 7 bytes will be a First Frame (no flow control in this mode)");
enableIso(*tester, "tester");
transmitIso(*tester, opt, payload);
break;
case Mode::Both:
logLine("Mode --both: firmware TX on tester, firmware flow-control on ECU");
enableIso(*tester, "tester");
enableIso(*ecu, "ECU");
receiveIso(*ecu, opt);
std::this_thread::sleep_for(100ms);
transmitIso(*tester, opt, payload);
break;
case Mode::None:
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(opt.listenMs));
closeDevice(tester);
closeDevice(ecu);
return 0;
}
+7
View File
@@ -15,6 +15,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
@@ -14,6 +14,13 @@ int main() {
auto devices = icsneo::FindAllDevices(); // This is type std::vector<std::shared_ptr<icsneo::Device>> auto devices = icsneo::FindAllDevices(); // This is type std::vector<std::shared_ptr<icsneo::Device>>
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+4 -2
View File
@@ -9,8 +9,10 @@ int main(int, char**) {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.size() == 0) { if(devices.empty()) {
std::cout << "No device found" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1; return -1;
} }
+7
View File
@@ -48,6 +48,13 @@ int main()
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for (auto &device : devices) for (auto &device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+7
View File
@@ -76,6 +76,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
+8 -1
View File
@@ -22,6 +22,13 @@ int main() {
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective // You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if(devices.empty()) {
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 0;
}
// List off the devices // List off the devices
for(auto& device : devices) for(auto& device : devices)
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl; std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
@@ -339,7 +346,7 @@ int main() {
if(val.has_value()) if(val.has_value())
std::cout << " - OK (" << val.value() << "V)" << std::endl; std::cout << " - OK (" << val.value() << "V)" << std::endl;
else else
std::cout << " - FAIL, it may need to be enabled in neoVI Explorer (" << icsneo::GetLastError() << ")" << std::endl; std::cout << " - FAIL, it may need to be enabled in ICS Device Manager (" << icsneo::GetLastError() << ")" << std::endl;
} }
} }
+3
View File
@@ -86,6 +86,9 @@ int main(int argc, const char** argv) {
} }
if(!device) { if(!device) {
std::cerr << "Failed to find device" << std::endl; std::cerr << "Failed to find device" << std::endl;
auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
std::cerr << usage; std::cerr << usage;
return -1; return -1;
} }
+4 -2
View File
@@ -216,8 +216,10 @@ int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if (devices.empty()) { if(devices.empty()) {
std::cout << "No devices found!" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return 1; return 1;
} }
@@ -260,8 +260,10 @@ int main() {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl; std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
if (devices.empty()) { if(devices.empty()) {
std::cerr << "No devices found!" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cerr << lastError << std::endl;
return 1; return 1;
} }
+3 -1
View File
@@ -106,7 +106,9 @@ int main(int argc, char* argv[]) {
auto devices = icsneo::FindAllDevices(); auto devices = icsneo::FindAllDevices();
if(devices.empty()) { if(devices.empty()) {
std::cout << "error: no devices found" << std::endl; auto lastError = icsneo::GetLastError();
if(lastError.getType() != icsneo::APIEvent::Type::NoErrorFound)
std::cout << lastError << std::endl;
return -1; return -1;
} }
+51
View File
@@ -0,0 +1,51 @@
import icsneopy
import time
#
# App errors are responses from the device indicating internal runtime errors
# NOTE: To trigger the app error in this example, disable the DW CAN 01 network on the device
# (e.g. with ICS Device Manager)
#
def apperror():
devices = icsneopy.find_all_devices()
if len(devices) == 0:
print("no devices found")
return False
device = devices[0]
print(f"selected {device}")
def on_apperror(message):
if message.get_app_error_type() != icsneopy.AppErrorType.NetworkNotEnabled:
print("unexpected app error type")
return
print(message.get_app_error_string())
filter = icsneopy.MessageFilter(icsneopy.Message.Type.AppError)
callback = icsneopy.MessageCallback(on_apperror, filter)
device.add_message_callback(callback)
if not device.open():
print("unable to open device")
return False
if not device.go_online():
print("unable to go online")
return False
frame = icsneopy.CANMessage()
frame.network = icsneopy.Network(icsneopy.Network.NetID.DWCAN_01)
frame.arbid = 0x22
frame.data = (0xAA, 0xBB, 0xCC)
if not device.transmit(frame):
print("failed to transmit frame")
return False
time.sleep(2) # wait for error to come back
return True
if __name__ == "__main__":
apperror()
+151
View File
@@ -0,0 +1,151 @@
import icsneopy
GPTP_PORT_MAP = {
icsneopy.Network.NetID.AE_01: (1, "AE 01"),
icsneopy.Network.NetID.AE_02: (2, "AE 02"),
icsneopy.Network.NetID.AE_03: (3, "AE 03"),
icsneopy.Network.NetID.AE_04: (4, "AE 04"),
icsneopy.Network.NetID.AE_05: (5, "AE 05"),
icsneopy.Network.NetID.AE_06: (6, "AE 06"),
icsneopy.Network.NetID.AE_07: (7, "AE 07"),
icsneopy.Network.NetID.AE_08: (8, "AE 08"),
icsneopy.Network.NetID.AE_09: (9, "AE 09"),
icsneopy.Network.NetID.AE_10: (10, "AE 10"),
icsneopy.Network.NetID.AE_11: (11, "AE 11"),
icsneopy.Network.NetID.AE_12: (12, "AE 12"),
icsneopy.Network.NetID.ETHERNET_01: (13, "Ethernet 01"),
icsneopy.Network.NetID.ETHERNET_02: (14, "Ethernet 02"),
icsneopy.Network.NetID.ETHERNET_03: (15, "Ethernet 03"),
icsneopy.Network.NetID.AE_13: (16, "AE 13"),
icsneopy.Network.NetID.AE_14: (17, "AE 14"),
icsneopy.Network.NetID.AE_15: (18, "AE 15"),
icsneopy.Network.NetID.AE_16: (19, "AE 16"),
}
PROFILE_NAMES = {
icsneopy.Settings.GTPPProfile.Standard: "Standard",
icsneopy.Settings.GTPPProfile.Automotive: "Automotive",
}
ROLE_NAMES = {
icsneopy.Settings.GTPPRole.Disabled: "Disabled",
icsneopy.Settings.GTPPRole.Passive: "Passive",
icsneopy.Settings.GTPPRole.Master: "Master",
icsneopy.Settings.GTPPRole.Slave: "Slave",
}
def prompt_int(prompt, default, lo, hi):
try:
raw = input(f"{prompt} [{default}]: ").strip()
if not raw:
return default
val = int(raw)
if lo <= val <= hi:
return val
except (ValueError, EOFError):
pass
print(f"Invalid input, using {default}.")
return default
def gptp_ports(device):
ports = []
for net in device.get_supported_tx_networks():
entry = GPTP_PORT_MAP.get(net.get_net_id())
if entry:
ports.append(entry)
return sorted(ports)
def print_settings(device):
s = device.settings
profile = s.get_gptp_profile()
role = s.get_gptp_role()
port = s.get_gptp_enabled_port()
synton = s.is_gptp_clock_syntonization_enabled()
print("\nCurrent gPTP settings:")
if profile is not None:
print(f" Profile: {PROFILE_NAMES.get(profile, profile)}")
if role is not None:
print(f" Role: {ROLE_NAMES.get(role, role)}")
if port is not None:
suffix = " (disabled)" if port == 0 else ""
print(f" Enabled port: {port}{suffix}")
if synton is not None:
print(f" Clock syntonization: {'enabled' if synton else 'disabled'}")
def configure(device):
if not device.settings.refresh():
print("error: failed to refresh settings")
return False
print_settings(device)
ports = gptp_ports(device)
print("\nAvailable gPTP ports (0 = disabled):")
print(" [0] Disabled")
for idx, name in ports:
print(f" [{idx}] {name}")
print("\nConfigure gPTP:")
profile = prompt_int(" Profile (0=Standard, 1=Automotive)", 1, 0, 1)
role = prompt_int(" Role (0=Disabled, 1=Passive, 2=Master, 3=Slave)", 3, 0, 3)
port = prompt_int(" Enabled port index", 0, 0, 19)
synton = prompt_int(" Clock syntonization (0=disabled, 1=enabled)", 0, 0, 1)
permanent = prompt_int("\nSave to EEPROM? (0=temporary, 1=permanent)", 0, 0, 1)
s = device.settings
profile_enum = list(PROFILE_NAMES.keys())[profile]
role_enum = list(ROLE_NAMES.keys())[role]
s.set_gptp_profile(profile_enum)
s.set_gptp_role(role_enum)
s.set_gptp_enabled_port(port)
s.set_gptp_clock_syntonization_enabled(bool(synton))
if not s.apply(not permanent):
print("error: failed to apply settings")
return False
print_settings(device)
return True
def main():
devices = icsneopy.find_all_devices()
if not devices:
print("error: no devices found")
return 1
gptp_devices = [d for d in devices if d.settings.get_gptp_profile() is not None]
if not gptp_devices:
print("error: no gPTP-capable devices found")
return 1
print("Available gPTP-capable devices:")
for i, d in enumerate(gptp_devices, 1):
print(f" [{i}] {d}")
choice = prompt_int("Select device", 1, 1, len(gptp_devices))
device = gptp_devices[choice - 1]
print(f"\nOpening {device}... ", end="", flush=True)
if not device.open():
print("failed")
return 1
print("OK")
try:
ok = configure(device)
finally:
print(f"\nClosing {device}")
device.close()
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())
+45
View File
@@ -0,0 +1,45 @@
import icsneopy
import time
#
# Main51 messages are device-originated notifications from the firmware's Main51 processor.
# This example filters for RX buffer overflow and TX FIFO overflow events.
#
def main51_filter():
devices = icsneopy.find_all_devices()
if len(devices) == 0:
print("no devices found")
return False
device = devices[0]
print(f"selected {device}")
def on_main51(message):
if not isinstance(message, icsneopy.Main51Message):
return
if message.command == icsneopy.Command.Main51RxBufferOverflow:
print("RX buffer overflow")
elif message.command == icsneopy.Command.Main51TxFifoOverflow:
print("TX FIFO overflow")
else:
print(f"Main51 command: {message.command}")
filter = icsneopy.Main51MessageFilter()
callback = icsneopy.MessageCallback(on_main51, filter)
device.add_message_callback(callback)
if not device.open():
print("unable to open device")
return False
if not device.go_online():
print("unable to go online")
return False
time.sleep(5)
return True
if __name__ == "__main__":
main51_filter()
+125 -25
View File
@@ -1,33 +1,133 @@
#ifndef _J2534_H #ifndef _J2534_H
#define _J2534_H #define _J2534_H
#include <cstdint>
namespace icsneo {
//J2534 Commands //J2534 Commands
#define J1534_NUM_PERIOD_TX_MSGS 128 #define J1534_NUM_PERIOD_TX_MSGS 128
#define J1534_NUM_PERIOD_RX_MSGS 128 #define J1534_NUM_PERIOD_RX_MSGS 128
#define J2534NVCMD_SetISJ2534 0
#define J2534NVCMD_SetISO5Baud 1 enum class J2534Command : uint8_t {
#define J2534NVCMD_SetISOFastInit 2 SetISJ2534 = 0,
#define J2534NVCMD_SetISOCheckSum 3 SetISO5Baud = 1,
#define J2534NVCMD_SetISO9141Parms 4 SetISOFastInit = 2,
#define J2534NVCMD_GetISO9141Parms 5 SetISOCheckSum = 3,
#define J2534NVCMD_ISO9141APIChkSum 6 SetISO9141Parms = 4,
#define J2534NVCMD_SetNetworkBaudRate 7 GetISO9141Parms = 5,
#define J2534NVCMD_GetNetworkBaudRate 8 ISO9141APIChkSum = 6,
#define J2534NVCMD_EnableTransmitEvent 9 SetNetworkBaudRate = 7,
#define J2534NVCMD_SetTransmitEvent 10 GetNetworkBaudRate = 8,
#define J2534NVCMD_BlueEnableStopFilters 11 EnableTransmitEvent = 9,
#define J2534NVCMD_Blue15765HWSupport 12 SetTransmitEvent = 10,
#define J2534NVCMD_GetTXBufferInfo 13 BlueEnableStopFilters = 11,
#define J2534NVCMD_GetEncryptionKey 14 Blue15765HWSupport = 12,
#define J2534NVCMD_SetMiscIOForVBATT 15 GetTXBufferInfo = 13,
#define J2534NVCMD_EnableISO_KW_Network 16 GetEncryptionKey = 14,
#define J2534NVCMD_SetJ1708CheckSum 17 SetMiscIOForVBATT = 15,
#define J2534NVCMD_GetTimestamp 18 EnableISO_KW_Network = 16,
#define J2534NVCMD_GetCANFDRate 19 SetJ1708CheckSum = 17,
#define J2534NVCMD_SetCANFDRate 20 GetTimestamp = 18,
#define J2534NVCMD_GetCANFDTermination 21 GetCANFDRate = 19,
#define J2534NVCMD_SetCANFDTermination 22 SetCANFDRate = 20,
#define J2534NVCMD_GetCANFDFormat 23 GetCANFDTermination = 21,
#define J2534NVCMD_SetCANFDFormat 24 SetCANFDTermination = 22,
GetCANFDFormat = 23,
SetCANFDFormat = 24
};
#pragma pack(push)
#pragma pack(1)
/**
* SubFrame Commands
*/
enum class J2534SubCommand : uint8_t {
Enable = 0,
SetupIso15765RxFilter = 1,
SetupIso15765TxMessageProperties = 2,
SetupIso15765TxMessageDataBytes = 3,
SetupCanRxFilter = 4,
SetupClearCanRxFilters = 5,
EnableFiltering = 6
};
typedef struct
{
uint16_t uiFilterMask0;
uint16_t uiFilterID0;
uint16_t uiFilterMask1;
uint16_t uiFilterID1;
uint16_t uiFilterMask2;
uint16_t uiFilterID2;
union {
/** Mask and value words if rx filter is datalink filter*/
struct
{
uint16_t uiFilterMask3;
uint16_t uiFilterID3;
uint16_t uiFilterMask4;
uint16_t uiFilterID4;
uint16_t uiFilterMask5;
uint16_t uiFilterID5;
uint16_t uiFilterMask6;
uint16_t uiFilterID6;
} datalink;
/** Mask and value bytes if rx filter is datalink filter*/
struct
{
uint8_t uiFilterMask_DB0;
uint8_t uiFilterMask_DB1;
uint8_t uiFilterID_DB0;
uint8_t uiFilterID_DB1;
uint8_t uiFilterMask_DB2;
uint8_t uiFilterMask_DB3;
uint8_t uiFilterID_DB2;
uint8_t uiFilterID_DB3;
uint8_t uiFilterMask_DB4;
uint8_t uiFilterMask_DB5;
uint8_t uiFilterID_DB4;
uint8_t uiFilterID_DB5;
uint8_t uiFilterMask_DB6;
uint8_t uiFilterMask_DB7;
uint8_t uiFilterID_DB6;
uint8_t uiFilterID_DB7;
} datalinkBytes;
/** Mask and value bytes if rx filter is Iso15765-2*/
struct
{
uint8_t uiFilterMask_DB0;
uint8_t uiFilterID_DB0;
uint8_t uiFilterMask_DB1;
uint8_t uiFilterID_DB1;
uint8_t uiFilterMask_DB2;
uint8_t uiFilterID_DB2;
uint8_t uiFilterMask_DB3;
uint8_t uiFilterID_DB3;
uint8_t uiFilterMask_DB4;
uint8_t uiFilterID_DB4;
uint8_t uiFilterMask_DB5;
uint8_t uiFilterID_DB5;
uint8_t uiFilterMask_DB6;
uint8_t uiFilterID_DB6;
uint8_t uiFilterMask_DB7;
uint8_t uiFilterID_DB7;
} iso15Bytes;
} args;
} MessageFilterBytes;
typedef struct
{
uint16_t idx;
uint16_t enabled;
uint16_t filterCount;
MessageFilterBytes fb;
uint16_t networkId;
} J2534_RxCanFilter;
#pragma pack(pop)
} // namespace icsneo
#endif #endif
+12 -5
View File
@@ -19,6 +19,7 @@ typedef struct {
#include <chrono> #include <chrono>
#include <string> #include <string>
#include <ostream> #include <ostream>
#include <memory>
namespace icsneo { namespace icsneo {
@@ -185,19 +186,25 @@ public:
Error = 0x30 Error = 0x30
}; };
APIEvent() : eventStruct({}), serial(), timepoint(), device(nullptr) {} APIEvent() : eventStruct({}), serial(), timepoint() {}
APIEvent(APIEvent::Type event, APIEvent::Severity severity, const Device* device = nullptr); APIEvent(APIEvent::Type event, APIEvent::Severity severity, std::weak_ptr<Device> device = {});
const neoevent_t* getNeoEvent() const noexcept { return &eventStruct; } const neoevent_t* getNeoEvent() const noexcept { return &eventStruct; }
Type getType() const noexcept { return Type(eventStruct.eventNumber); } Type getType() const noexcept { return Type(eventStruct.eventNumber); }
Severity getSeverity() const noexcept { return Severity(eventStruct.severity); } Severity getSeverity() const noexcept { return Severity(eventStruct.severity); }
std::string getDescription() const noexcept { return std::string(eventStruct.description); } std::string getDescription() const noexcept { return std::string(eventStruct.description); }
const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide event const Device* getDevice() const noexcept { // Will return nullptr if this is an API-wide event
auto shared = device.lock();
return (shared) ? shared.get() : nullptr;
}
EventTimePoint getTimestamp() const noexcept { return timepoint; } EventTimePoint getTimestamp() const noexcept { return timepoint; }
void downgradeFromError() noexcept; void downgradeFromError() noexcept;
bool isForDevice(const Device* forDevice) const noexcept { return forDevice == device; } bool isForDevice(const Device* forDevice) const noexcept {
auto shared = device.lock();
return shared && (shared.get() == forDevice);
}
bool isForDevice(std::string serial) const noexcept; bool isForDevice(std::string serial) const noexcept;
// As opposed to getDescription, this will also add text such as "neoVI FIRE 2 CY2468 Error: " to fully describe the problem // As opposed to getDescription, this will also add text such as "neoVI FIRE 2 CY2468 Error: " to fully describe the problem
@@ -213,7 +220,7 @@ private:
neoevent_t eventStruct; neoevent_t eventStruct;
std::string serial; std::string serial;
EventTimePoint timepoint; EventTimePoint timepoint;
const Device* device; std::weak_ptr<Device> device;
void init(APIEvent::Type event, APIEvent::Severity); void init(APIEvent::Type event, APIEvent::Severity);
}; };
+1 -1
View File
@@ -56,7 +56,7 @@ public:
APIEvent getLastError(); APIEvent getLastError();
void add(APIEvent event); void add(APIEvent event);
void add(APIEvent::Type type, APIEvent::Severity severity, const Device* forDevice = nullptr) { void add(APIEvent::Type type, APIEvent::Severity severity, std::weak_ptr<Device> forDevice = {}) {
add(APIEvent(type, severity, forDevice)); add(APIEvent(type, severity, forDevice));
} }
+38
View File
@@ -0,0 +1,38 @@
#ifndef __HEARTBEAT_H__
#define __HEARTBEAT_H__
#ifdef __cplusplus
#include <thread>
#include <condition_variable>
#include <mutex>
namespace icsneo {
class Device;
class Heartbeat {
public:
Heartbeat(Device& device);
~Heartbeat();
private:
enum class Mode {
Passive, // ResetStatus messages arrive without requesting
Active, // RequestStatusUpdate needs to be sent
};
Device& device;
const Mode mode;
bool stop = false;
std::mutex mutex;
std::condition_variable cv;
std::thread thread;
void run();
};
} // icsneo
#endif // __cplusplus
#endif // __HEARTBEAT_H__
+249
View File
@@ -0,0 +1,249 @@
// --------------------------------------------------------------------------
// COPYRIGHT INTREPID CONTROL SYSTEMS, INC. (c) 1994-20xx
// Confidential and proprietary. This document and its contents are the
// property of Intrepid Control Systems, Inc. It is not to be copied,
// distributed, or otherwise disclosed or used without the prior written
// consent of Intrepid Control Systems Inc.
// All rights reserved.
// --------------------------------------------------------------------------
// SPY Status Bit Definitions
// Generated automatically - DO NOT MODIFY
// Modify cicsSpyStatusBits_config.yml and run cicsSpyStatusBits_gen.py
// Generated on: 2025-07-14 14:31:40
#ifndef CICSSPYSTATUSBITS_H_
#define CICSSPYSTATUSBITS_H_ 1
// WARNING: The following bit conflicts were detected:
// spystatus value 0x10000000: // VSI value 'SPY_STATUS_VSI_IFR_CRC_BIT' conflicts with common value 'SPY_STATUS_PDU'
// spystatus value 0x10000000: // A2B value 'SPY_STATUS_A2B_CONTROL' conflicts with common value 'SPY_STATUS_PDU'
// spystatus value 0x08: // A2B value 'SPY_STATUS_A2B_SCF_VALID_WAITING' conflicts with common value 'SPY_STATUS_REMOTE_FRAME'
// spystatus value 0x40000000: // A2B value 'SPY_STATUS_A2B_UPSTREAM' conflicts with common value 'SPY_STATUS_HIGH_SPEED'
// spystatus value 0x10000000: // FLEXRAY value 'SPY_STATUS_FLEXRAY_PDU' conflicts with common value 'SPY_STATUS_PDU'
// spystatus value 0x40000000: // FLEXRAY value 'SPY_STATUS_FLEXRAY_PDU_UPDATE_BIT_SET' conflicts with common value 'SPY_STATUS_HIGH_SPEED'
// spystatus value 0x08: // FLEXRAY value 'SPY_STATUS_FLEXRAY_PDU_NO_UPDATE_BIT' conflicts with common value 'SPY_STATUS_REMOTE_FRAME'
// Glyph definitions
// '|' - byte divider
// '.' - nibble divider
// '-' - unused bit
// 'o' - common bit
// 'x' - protocol specific bit
// '!' - conflict bit
// SPYSTATUS bit definitions
// SPYSTATUS - Common bits
// |oo-o.oooo|oooo.oooo|oooo.oo-o|oo-o.oooo|
#define SPY_STATUS_GLOBAL_ERR 0x01 // Global error flag
#define SPY_STATUS_TX_MSG 0x02 // Transmitted message
#define SPY_STATUS_XTD_FRAME 0x04 // Extended frame
#define SPY_STATUS_REMOTE_FRAME 0x08 // Remote frame
#define SPY_STATUS_CRC_ERROR 0x10 // CRC error
#define SPY_STATUS_INCOMPLETE_FRAME 0x40 // Incomplete frame
#define SPY_STATUS_LOST_ARBITRATION 0x80 // Lost arbitration
#define SPY_STATUS_UNDEFINED_ERROR 0x0100 // Undefined error
#define SPY_STATUS_BUS_RECOVERED 0x0400 // Bus recovered
#define SPY_STATUS_BUS_SHORTED_PLUS 0x0800 // Bus shorted to plus
#define SPY_STATUS_BUS_SHORTED_GND 0x1000 // Bus shorted to ground
#define SPY_STATUS_CHECKSUM_ERROR 0x2000 // Checksum error
#define SPY_STATUS_BAD_MESSAGE_BIT_TIME_ERROR 0x4000 // Bad message bit time error
#define SPY_STATUS_TX_NOMATCH 0x8000 // TX no match
#define SPY_STATUS_COMM_IN_OVERFLOW 0x010000 // Communication input overflow
#define SPY_STATUS_EXPECTED_LEN_MISMATCH 0x020000 // Expected length mismatch
#define SPY_STATUS_MSG_NO_MATCH 0x040000 // Message no match
#define SPY_STATUS_BREAK 0x080000 // Break detected
#define SPY_STATUS_AVSI_REC_OVERFLOW 0x100000 // AVSI record overflow
#define SPY_STATUS_TEST_TRIGGER 0x200000 // Test trigger
#define SPY_STATUS_AUDIO_COMMENT 0x400000 // Audio comment
#define SPY_STATUS_GPS_DATA 0x800000 // GPS data
#define SPY_STATUS_ANALOG_DIGITAL_INPUT 0x01000000 // Analog digital input
#define SPY_STATUS_TEXT_COMMENT 0x02000000 // Text comment
#define SPY_STATUS_NETWORK_MESSAGE_TYPE 0x04000000 // Network message type
#define SPY_STATUS_VSI_TX_UNDERRUN 0x08000000 // VSI TX underrun
#define SPY_STATUS_PDU 0x10000000 // PDU message
#define SPY_STATUS_HIGH_SPEED 0x40000000 // High speed
#define SPY_STATUS_EXTENDED 0x80000000 // Extended - if this bit is set than decode StatusBitField3 in AckBytes
// SPYSTATUS - A2B protocol bits
// |o!x!.oooo|oooo.oooo|oooo.oo-o|oo-o.!ooo|
#define SPY_STATUS_A2B_SCF_VALID_WAITING 0x08 // A2B SCF valid waiting
#define SPY_STATUS_A2B_CONTROL 0x10000000 // A2B control message
#define SPY_STATUS_A2B_MONITOR 0x20000000 // A2B monitor message
#define SPY_STATUS_A2B_UPSTREAM 0x40000000 // A2B upstream message
// SPYSTATUS - CAN protocol bits
// |ooxo.oooo|oooo.oooo|oooo.ooxo|ooxo.oooo|
#define SPY_STATUS_CAN_ERROR_PASSIVE 0x20 // CAN error passive state
#define SPY_STATUS_CAN_BUS_OFF 0x0200 // CAN bus off state
#define SPY_STATUS_CANFD 0x20000000 // CAN FD frame
// SPYSTATUS - ETHERNET protocol bits
// |oo-o.oooo|oooo.oooo|oooo.oo-o|ooxo.oooo|
#define SPY_STATUS_HEADERCRC_ERROR 0x20 // Header CRC error
// SPYSTATUS - FLEXRAY protocol bits
// |o!-!.oooo|oooo.oooo|oooo.oo-o|oo-o.!ooo|
#define SPY_STATUS_FLEXRAY_PDU_NO_UPDATE_BIT 0x08 // FlexRay PDU no update bit
#define SPY_STATUS_FLEXRAY_PDU 0x10000000 // FlexRay PDU (alias for SPY_STATUS_PDU)
#define SPY_STATUS_FLEXRAY_PDU_UPDATE_BIT_SET 0x40000000 // FlexRay PDU update bit set
// SPYSTATUS - LIN protocol bits
// |ooxo.oooo|oooo.oooo|oooo.oo-o|oo-o.oooo|
#define SPY_STATUS_LIN_MASTER 0x20000000 // LIN master message
// SPYSTATUS - VSI protocol bits
// |oox!.oooo|oooo.oooo|oooo.oo-o|oo-o.oooo|
#define SPY_STATUS_VSI_IFR_CRC_BIT 0x10000000 // VSI IFR CRC bit
#define SPY_STATUS_INIT_MESSAGE 0x20000000 // Initialization message
// SPYSTATUS2 bit definitions
// SPYSTATUS2 - Common bits
// |----.----|---o.--oo|----.----|----.oooo|
#define SPY_STATUS2_HAS_VALUE 0x01
#define SPY_STATUS2_VALUE_IS_BOOLEAN 0x02
#define SPY_STATUS2_HIGH_VOLTAGE 0x04
#define SPY_STATUS2_LONG_MESSAGE 0x08
#define SPY_STATUS2_GLOBAL_CHANGE 0x010000
#define SPY_STATUS2_ERROR_FRAME 0x020000
#define SPY_STATUS2_END_OF_LONG_MESSAGE 0x100000
// SPYSTATUS2 - CAN protocol bits
// |----.----|-xxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_CAN_ISO15765_LOGICAL_FRAME 0x200000
#define SPY_STATUS2_CAN_HAVE_LINK_DATA 0x400000
// SPYSTATUS2 - ETHERNET protocol bits
// |xxxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_ETHERNET_CRC_ERROR 0x200000
#define SPY_STATUS2_ETHERNET_FRAME_TOO_SHORT 0x400000
#define SPY_STATUS2_ETHERNET_FCS_AVAILABLE 0x800000 // This frame contains FCS (4 bytes) obtained from ICS Ethernet hardware (ex. RAD-STAR)
#define SPY_STATUS2_ETHERNET_NO_PADDING 0x01000000
#define SPY_STATUS2_ETHERNET_PREEMPTION_ENABLED 0x02000000
#define SPY_STATUS2_ETHERNET_UPDATE_CHECKSUMS 0x04000000
#define SPY_STATUS2_ETHERNET_MANUALFCS_ENABLED 0x08000000
#define SPY_STATUS2_ETHERNET_FCS_VERIFIED 0x10000000
#define SPY_STATUS2_ETHERNET_T1S_SYMBOL 0x20000000
#define SPY_STATUS2_ETHERNET_T1S_BURST 0x40000000
#define SPY_STATUS2_ETHERNET_T1S_ETHERNET 0x80000000
// SPYSTATUS2 - FLEXRAY protocol bits
// |----.-xxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_FLEXRAY_TX_AB 0x200000
#define SPY_STATUS2_FLEXRAY_TX_AB_NO_A 0x400000
#define SPY_STATUS2_FLEXRAY_TX_AB_NO_B 0x800000
#define SPY_STATUS2_FLEXRAY_TX_AB_NO_MATCH 0x01000000
#define SPY_STATUS2_FLEXRAY_NO_CRC 0x02000000
#define SPY_STATUS2_FLEXRAY_NO_HEADERCRC 0x04000000 //
// SPYSTATUS2 - I2C protocol bits
// |----.----|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_I2C_ERR_TIMEOUT 0x200000
#define SPY_STATUS2_I2C_ERR_NACK 0x400000
#define SPY_STATUS2_I2C_DIR_READ 0x800000
// SPYSTATUS2 - ISO protocol bits
// |-xxx.x---|---o.--oo|----.----|----.oooo|
#define SPY_STATUS2_ISO_FRAME_ERROR 0x08000000 // ISO frame error
#define SPY_STATUS2_ISO_OVERFLOW_ERROR 0x10000000 // ISO overflow error
#define SPY_STATUS2_ISO_PARITY_ERROR 0x20000000 // ISO parity error
#define SPY_STATUS2_ISO_RX_TIMEOUT_ERROR 0x40000000 // ISO specific timeout error
// SPYSTATUS2 - LIN protocol bits
// |xxxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_LIN_ERR_RX_BREAK_NOT_0 0x200000 // LIN RX break not 0 error
#define SPY_STATUS2_LIN_ERR_RX_BREAK_TOO_SHORT 0x400000 // LIN RX break too short error
#define SPY_STATUS2_LIN_ERR_RX_SYNC_NOT_55 0x800000 // LIN RX sync not 0x55 error
#define SPY_STATUS2_LIN_ERR_RX_DATA_GREATER_8 0x01000000 // LIN RX data greater than 8 bytes error
#define SPY_STATUS2_LIN_ERR_TX_RX_MISMATCH 0x02000000 // LIN TX/RX mismatch error
#define SPY_STATUS2_LIN_ERR_MSG_ID_PARITY 0x04000000 // LIN message ID parity error
#define SPY_STATUS2_LIN_SYNC_FRAME_ERROR 0x08000000 // LIN sync frame error
#define SPY_STATUS2_LIN_ID_FRAME_ERROR 0x10000000 // LIN ID frame error
#define SPY_STATUS2_LIN_SLAVE_BYTE_ERROR 0x20000000 // LIN slave byte error
#define SPY_STATUS2_LIN_RX_TIMEOUT_ERROR 0x40000000 // RX timeout error
#define SPY_STATUS2_LIN_NO_SLAVE_DATA 0x80000000 // LIN no slave data
// SPYSTATUS2 - MDIO protocol bits
// |-xxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_MDIO_ERR_TIMEOUT 0x200000
#define SPY_STATUS2_MDIO_JOB_CANCELLED 0x400000
#define SPY_STATUS2_MDIO_INVALID_BUS 0x800000
#define SPY_STATUS2_MDIO_INVALID_PHYADDR 0x01000000
#define SPY_STATUS2_MDIO_INVALID_REGADDR 0x02000000
#define SPY_STATUS2_MDIO_UNSUPPORTED_CLAUSE 0x04000000
#define SPY_STATUS2_MDIO_UNSUPPORTED_OPCODE 0x08000000
#define SPY_STATUS2_MDIO_OVERFLOW 0x10000000
#define SPY_STATUS2_MDIO_CLAUSE45 0x20000000
#define SPY_STATUS2_MDIO_READ 0x40000000
// SPYSTATUS2 - MOST protocol bits
// |xxxx.xxxx|xxxo.--oo|----.----|----.oooo|
#define SPY_STATUS2_MOST_PACKET_DATA 0x200000
#define SPY_STATUS2_MOST_STATUS 0x400000 // reflects changes in light/lock/MPR/SBC/etc...
#define SPY_STATUS2_MOST_LOW_LEVEL 0x800000 // MOST low level message, allocs, deallocs, remote requests...*/
#define SPY_STATUS2_MOST_CONTROL_DATA 0x01000000
#define SPY_STATUS2_MOST_MHP_USER_DATA 0x02000000 // MOST HIGH User Data Frame
#define SPY_STATUS2_MOST_MHP_CONTROL_DATA 0x04000000 // MOST HIGH Control Data
#define SPY_STATUS2_MOST_I2S_DUMP 0x08000000
#define SPY_STATUS2_MOST_TOO_SHORT 0x10000000
#define SPY_STATUS2_MOST_MOST50 0x20000000 // absence of MOST50 and MOST150 implies it's MOST25
#define SPY_STATUS2_MOST_MOST150 0x40000000
#define SPY_STATUS2_MOST_CHANGED_PAR 0x80000000 // first byte in ack reflects what changed.
// SPYSTATUS2 - WBMS protocol bits
// |----.----|--xo.--oo|----.----|----.oooo|
#define SPY_STATUS2_WBMS_API_IS_CALLBACK 0x200000
// SPYSTATUS3 bit definitions
// SPYSTATUS3 - CAN protocol bits
// |----.----|-xxx.xxxx|-xxx.xxxx|----.-xxx|
#define SPY_STATUS3_CAN_ERR_PASSIVE 0x01 // CAN error passive state: typically when error counter is > 127
#define SPY_STATUS3_CAN_BUS_OFF 0x02 // CAN bus off state
#define SPY_STATUS3_CAN_ERR_WARNING 0x04 // CAN error warning: typically when error counter is > 96
#define SPY_STATUS3_CAN_DATAERR_STUFF_ERROR 0x0100 // CAN stuff error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_FORM_ERROR 0x0200 // CAN form error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_ACK_ERROR 0x0400 // CAN ack error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_BIT1_ERROR 0x0800 // CAN bit1 error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_BIT0_ERROR 0x1000 // CAN bit0 error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_CRC_ERROR 0x2000 // CAN CRC error during the data payload phase
#define SPY_STATUS3_CAN_DATAERR_NOCHANGE 0x4000 // CAN data error occurred before and no change yet
#define SPY_STATUS3_CAN_GENERR_STUFF_ERROR 0x010000 // CAN stuff error at the general frame level
#define SPY_STATUS3_CAN_GENERR_FORM_ERROR 0x020000 // CAN form error at the general frame level
#define SPY_STATUS3_CAN_GENERR_ACK_ERROR 0x040000 // CAN ack error at the general frame level
#define SPY_STATUS3_CAN_GENERR_BIT1_ERROR 0x080000 // CAN bit1 error at the general frame level
#define SPY_STATUS3_CAN_GENERR_BIT0_ERROR 0x100000 // CAN bit0 error at the general frame level
#define SPY_STATUS3_CAN_GENERR_CRC_ERROR 0x200000 // CAN CRC error at the general frame level
#define SPY_STATUS3_CAN_GENERR_NOCHANGE 0x400000 // CAN frame Error occurred before and no change yet
// SPYSTATUS3 - CANFD protocol bits
// |----.----|----.----|----.----|---x.xxxx|
#define SPY_STATUS3_CANFD_ESI 0x01 // CAN FD Error State Indicator (ESI) reflects the error state of the transmitting node
#define SPY_STATUS3_CANFD_IDE 0x02 // CAN FD Identifier Extension (IDE) indicates if standard or extended IDs are in use
#define SPY_STATUS3_CANFD_RTR 0x04
#define SPY_STATUS3_CANFD_FDF 0x08 // CAN FD Format (FDF) flag -- distinguishes classic CAN from CANFD
#define SPY_STATUS3_CANFD_BRS 0x10 // CANFD Baud Rate Select (BRS) flag, indicates if the data portion transmits at a higher bitrate
// SPYSTATUS3 - ETHERNET protocol bits
// |----.----|----.----|----.----|----.--xx|
#define SPY_STATUS3_ETHERNET_TX_COLLISION 0x01
#define SPY_STATUS3_ETHERNET_T1S_WAKE 0x02
// SPYSTATUS3 - LIN protocol bits
// |----.----|----.----|----.----|----.-xxx|
#define SPY_STATUS3_LIN_JUST_BREAK_SYNC 0x01
#define SPY_STATUS3_LIN_SLAVE_DATA_TOO_SHORT 0x02
#define SPY_STATUS3_LIN_ONLY_UPDATE_SLAVE_TABLE_ONCE 0x04
// SPYSTATUS4 bit definitions
// SPYSTATUS4 - ETHERNET protocol bits
// |----.----|----.----|----.----|----.--xx|
#define SPY_STATUS4_ETH_CRC_ERROR 0x01 // Ethernet CRC error
#define SPY_STATUS4_ETH_FRAME_TOO_LONG 0x02 // Ethernet frame too long
#endif // CICSSPYSTATUSBITS_H_
+22
View File
@@ -6,6 +6,22 @@
namespace icsneo { namespace icsneo {
enum class Command : uint8_t { enum class Command : uint8_t {
// Device-originated Main51 event/error notifications (device -> host)
Main51RxBufferOverflow = 0x01,
Main51StartCmd = 0x02,
Main51TxFifoOverflow = 0x03,
Main51BulkInNoData = 0x04,
Main51SetModeComplete = 0x05,
Main51ReadEeprom = 0x06,
// 0x07, 0x08, 0x09 reserved for host->device commands below
Main51CmdDone = 0x0A,
Main51ErrStatus = 0x0B,
Main51ReadSectorBuff = 0x0C,
Main51WriteSectorBuff = 0x0D,
Main51MmcProcessDone = 0x0E,
Main51ReInitDone = 0x0F,
// Host-originated commands (host -> device)
EnableNetworkCommunication = 0x07, EnableNetworkCommunication = 0x07,
EnableNetworkCommunicationEx = 0x08, EnableNetworkCommunicationEx = 0x08,
KeepAlive = 0x09, KeepAlive = 0x09,
@@ -27,6 +43,7 @@ enum class Command : uint8_t {
GetLogicalDiskInfo = 0xBB, // Previously known as RED_CMD_GET_SDCARD_INFO GetLogicalDiskInfo = 0xBB, // Previously known as RED_CMD_GET_SDCARD_INFO
RequestStatusUpdate = 0xBC, RequestStatusUpdate = 0xBC,
ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX
J2534Command = 0xD7, // Previously known as RED_CMD_J2534_EXTENSION
SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR
RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH
WiVICommand = 0xDD, // Previously known as RED_CMD_WIVI_COMM WiVICommand = 0xDD, // Previously known as RED_CMD_WIVI_COMM
@@ -57,13 +74,18 @@ enum class ExtendedCommand : uint16_t {
GetComponentVersions = 0x001A, GetComponentVersions = 0x001A,
SoftwareUpdate = 0x001B, SoftwareUpdate = 0x001B,
Reboot = 0x001C, Reboot = 0x001C,
ReadGenericAPIStatus = 0x001D,
SetRootFSEntryFlags = 0x0027, SetRootFSEntryFlags = 0x0027,
TransmitCoreminiMessage = 0x0028, TransmitCoreminiMessage = 0x0028,
ReadGenericAPIData = 0x002E,
WriteGenericAPICommand = 0x002F,
GenericBinaryInfo = 0x0030, GenericBinaryInfo = 0x0030,
LiveData = 0x0035, LiveData = 0x0035,
ExecuteSPIPortKeyOperation = 0x003C,
RequestTC10Wake = 0x003D, RequestTC10Wake = 0x003D,
RequestTC10Sleep = 0x003E, RequestTC10Sleep = 0x003E,
GetTC10Status = 0x003F, GetTC10Status = 0x003F,
GetAllMACAddresses = 0x0040,
ProtobufAPI = 0x0041, ProtobufAPI = 0x0041,
TransmitMessage = 0x0042, TransmitMessage = 0x0042,
}; };

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