Compare commits

...

31 Commits

Author SHA1 Message Date
vits71 dedf68879f
Merge 739ff4d637 into a0c8cc62df 2025-02-19 20:12:37 -08:00
Kyle Schwarz a0c8cc62df Bindings: Python: Add coremini functions 2025-02-19 17:38:07 +00:00
Kyle Schwarz 77b3564677 Communication: Add missing short format commands 2025-02-19 00:20:49 -05:00
Kyle Schwarz 051063e684 RADGigastar: Add disk support 2025-02-19 00:18:41 -05:00
Kyle Schwarz 7c1cfde6a0 CI: Remove duplicate DOCKER_HOST 2025-02-19 00:16:36 -05:00
Yasser Yassine d4995fa2a9 Device: Fix heartbeat thread join location 2025-02-19 05:15:23 +00:00
Kyle Schwarz fb5c4babce CI: Remove hardware tests 2025-02-19 05:12:51 +00:00
Kurt Wachowski 4ba1a1e1dd Resolve "Add MACsec support" 2025-02-17 20:44:58 +00:00
Kyle Schwarz 6b9a687ff9 Bindings: Python: Use static MSVC runtime library 2025-02-11 16:43:00 -05:00
Kyle Schwarz 02b5dafca9 Bindings: Python: Simplify debug process 2025-02-11 12:43:30 -05:00
David Rebbe f04cd16bee Platform: Improve Windows wstring support 2025-02-06 18:43:51 +00:00
Jonathan Schwartz c5ba2d8d32 Communication: Add missing CAN error types 2025-02-04 15:15:44 +00:00
Kyle Schwarz a22791c9e0 CI: Move Windows jobs 2025-02-03 17:16:30 -05:00
Kyle Schwarz dc2a364afb Bindings: Python: Fix API docs since adding stubs 2025-01-29 14:53:18 -05:00
Kyle Schwarz 114b664d78 All: Welcome to 2025 2025-01-15 16:46:07 -05:00
vits71 739ff4d637
Merge branch 'intrepidcs:master' into Npcap-fix 2025-01-11 23:15:28 +01:00
Kyle Schwarz 2acf248583 Bindings: Python: Add stubs 2025-01-09 00:14:46 -05:00
Kyle Schwarz f18aa00322 Communication: Add EthernetStatusMessage 2025-01-06 14:12:19 -05:00
Jonathan Schwartz 87baa97c3f Device: Fix ComponentVersion retrieval 2025-01-06 19:06:11 +00:00
Jonathan Schwartz 8dcbbe0d72 NeoVIConnect: Add ComponentVersions support 2025-01-06 14:51:42 +00:00
Kyle Schwarz b624d06ca0 Driver: FTD3XX: Fix close() 2024-12-30 14:14:23 -05:00
Kyle Schwarz c249df8756 Bindings: Python: Add CANErrorCountMessage 2024-12-23 10:28:19 -05:00
Kyle Schwarz b2161211c5 Bindings: Python: Add Message::Type MessageFilter 2024-12-20 18:28:41 -05:00
Kyle Schwarz 0ee8a990a7 Bindings: Python: Fix get_gptp_status default arg 2024-12-20 18:28:22 -05:00
Yasser Yassine dc0f16b1d2 Communication: Add GPTPStatus 2024-12-20 23:22:25 +00:00
Kyle Schwarz c4ce803d62 LINMessage: Fix timestamp scaling 2024-12-19 15:54:27 -05:00
Kyle Schwarz 34cacf4cf2 EthernetMessage: Fix TX receipts
Fixes
- HardwareEthernetPacket packing
- EthernetMessage::fcs
2024-12-13 12:55:57 -05:00
Kyle Schwarz 4157558e84 Bindings: Python: Drop GIL for Device calls
Avoids an ABBA deadlock with the GIL and messageCallbacksLock
2024-12-12 11:12:55 -05:00
Kyle Schwarz 40b85488dc TCP: Add LIBICSNEO_DISABLE_TCP env option 2024-12-11 17:25:36 -05:00
Kyle Schwarz 7584563002 Bindings: Python: Add default MessageFilter constructor 2024-12-11 17:22:09 -05:00
Vít Šembera e233233b94 Fixed Npcap related errors in PCAPDLL::PCAPDLL() 2024-07-18 13:26:39 +02:00
76 changed files with 2183 additions and 315 deletions

View File

@ -4,7 +4,6 @@ variables:
stages: stages:
- build - build
- unit_test - unit_test
- hardware_test
- deploy - deploy
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -21,7 +20,7 @@ build windows/x64:
- build - build
expire_in: 3 days expire_in: 3 days
tags: tags:
- icsneo-windows - libicsneo-win-x64
unit_test windows/x64: unit_test windows/x64:
stage: unit_test stage: unit_test
@ -32,7 +31,7 @@ unit_test windows/x64:
needs: needs:
- build windows/x64 - build windows/x64
tags: tags:
- icsneo-windows - libicsneo-win-x64
timeout: 5m timeout: 5m
build windows/x86: build windows/x86:
@ -45,7 +44,7 @@ build windows/x86:
- build - build
expire_in: 3 days expire_in: 3 days
tags: tags:
- icsneo-windows - libicsneo-win-x64
unit_test windows/x86: unit_test windows/x86:
stage: unit_test stage: unit_test
@ -56,7 +55,7 @@ unit_test windows/x86:
needs: needs:
- build windows/x86 - build windows/x86
tags: tags:
- icsneo-windows - libicsneo-win-x64
timeout: 5m timeout: 5m
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -307,119 +306,6 @@ unit_test linux/fedora/39/amd64/clang:
needs: needs:
- build linux/fedora/39/amd64/clang - build linux/fedora/39/amd64/clang
.hw_test: &hw_test
stage: hardware_test
tags:
- libicsneo_hil
timeout: 5m
script:
- echo $GUEST_OS_TAG
- echo $DEVICE_PORT
- /opt/libvirt-driver/prepare.sh
- /opt/libvirt-driver/run.sh
after_script:
- /opt/libvirt-driver/cleanup.sh
allow_failure: true
.fedora38_needs: &fedora38_needs
needs:
- job: build linux/fedora/38/amd64/clang
artifacts: true
hardware_test fedora38-red2:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_A
hardware_test fedora38-vcan42:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_D
hardware_test fedora38-fire3:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: ETH_B
hardware_test fedora38-vcan42-EL:
<<: *hw_test
<<: *fedora38_needs
variables:
GUEST_OS_TAG: fedora38
DEVICE_PORT: USB_C
.ubuntu2204_needs: &ubuntu2204_needs
needs:
- job: build linux/ubuntu/2204/amd64/clang
artifacts: true
hardware_test ubuntu2204-red2:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_A
hardware_test ubuntu2204-vcan42:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_D
hardware_test ubuntu2204-fire3:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: ETH_B
hardware_test ubuntu2204-vcan42-EL:
<<: *hw_test
<<: *ubuntu2204_needs
variables:
GUEST_OS_TAG: ubuntu22.04
DEVICE_PORT: USB_C
.win10_needs: &win10_needs
needs:
- job: build windows/x64
artifacts: true
hardware_test win10-red2:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_A
hardware_test win10-vcan42:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_D
hardware_test win10-fire3:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: ETH_B
hardware_test win10-vcan42-EL:
<<: *hw_test
<<: *win10_needs
variables:
GUEST_OS_TAG: win10
DEVICE_PORT: USB_C
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Python Module # Python Module
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12) cmake_minimum_required(VERSION 3.16)
project(libicsneo VERSION 0.3.0) project(libicsneo VERSION 0.3.0)
cmake_policy(SET CMP0074 NEW) cmake_policy(SET CMP0074 NEW)
@ -7,14 +7,13 @@ if(POLICY CMP0135)
endif() endif()
option(LIBICSNEO_BUILD_UNIT_TESTS "Build unit tests." OFF) option(LIBICSNEO_BUILD_UNIT_TESTS "Build unit tests." OFF)
option(LIBICSNEO_BUILD_SYSTEM_TESTS "Build system tests." OFF)
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF) option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON) option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON) option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON) option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON) option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON) option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap") set(LIBICSNEO_NPCAP_INCLUDE_DIR "C:/Users/Vit/source/repos/npcap-sdk-1.13/Include" CACHE STRING "Npcap include directory; set to build with Npcap")
# Device Drivers # Device Drivers
# You almost certainly don't want firmio for your build, # You almost certainly don't want firmio for your build,
@ -111,6 +110,7 @@ endif()
if(WIN32) if(WIN32)
set(PLATFORM_SRC set(PLATFORM_SRC
platform/windows/strings.cpp
platform/windows/registry.cpp platform/windows/registry.cpp
) )
@ -246,6 +246,9 @@ set(SRC_FILES
communication/message/linmessage.cpp communication/message/linmessage.cpp
communication/message/livedatamessage.cpp communication/message/livedatamessage.cpp
communication/message/tc10statusmessage.cpp communication/message/tc10statusmessage.cpp
communication/message/gptpstatusmessage.cpp
communication/message/ethernetstatusmessage.cpp
communication/message/macsecmessage.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
@ -273,6 +276,7 @@ set(SRC_FILES
communication/driver.cpp communication/driver.cpp
communication/livedata.cpp communication/livedata.cpp
communication/ringbuffer.cpp communication/ringbuffer.cpp
communication/crc32.cpp
device/extensions/flexray/extension.cpp device/extensions/flexray/extension.cpp
device/extensions/flexray/controller.cpp device/extensions/flexray/controller.cpp
device/idevicesettings.cpp device/idevicesettings.cpp
@ -525,6 +529,7 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/livedataencoderdecodertest.cpp test/unit/livedataencoderdecodertest.cpp
test/unit/ringbuffertest.cpp test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp test/unit/apperrordecodertest.cpp
test/unit/windowsstrings.cpp
) )
target_link_libraries(libicsneo-unit-tests gtest gtest_main) target_link_libraries(libicsneo-unit-tests gtest gtest_main)
@ -537,22 +542,6 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
add_test(NAME libicsneo-unit-test-suite COMMAND libicsneo-unit-tests) add_test(NAME libicsneo-unit-test-suite COMMAND libicsneo-unit-tests)
endif() endif()
if(LIBICSNEO_BUILD_SYSTEM_TESTS)
if(DEFINED ENV{LIBICSNEO_SYSTEM_TESTS})
include(FetchContent)
file(MAKE_DIRECTORY test/system)
FetchContent_Declare(
SystemTests
GIT_REPOSITORY $ENV{LIBICSNEO_SYSTEM_TESTS}
GIT_TAG main
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test/system
)
FetchContent_MakeAvailable(SystemTests)
else()
message("System test repo not defined!")
endif()
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)

30
LICENSE
View File

@ -1,13 +1,29 @@
Copyright 2018-2024 Intrepid Control Systems, Inc. Copyright (c) 2018-2025 Intrepid Control Systems, Inc.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
4. It is forbidden to use this library or derivatives to interface with vehicle networking hardware not produced by Intrepid Control Systems, Inc. 4. It is forbidden to use this library or derivatives to interface with vehicle
networking hardware not produced by Intrepid Control Systems, Inc.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -29,7 +29,7 @@ BEGIN
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API" VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneoc.dll" VALUE "InternalName", "icsneoc.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024" VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2025"
VALUE "OriginalFilename", "icsneoc.dll" VALUE "OriginalFilename", "icsneoc.dll"
VALUE "ProductName", "libicsneo" VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR VALUE "ProductVersion", VER_PRODUCTVERSION_STR

View File

@ -120,6 +120,7 @@ static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device."; static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device."; static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device.";
static constexpr const char* MODE_NOT_FOUND = "The mode was not found."; static constexpr const char* MODE_NOT_FOUND = "The mode was not found.";
static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is not supported on this device.";
// Transport Errors // Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed."; static constexpr const char* FAILED_TO_READ = "A read operation failed.";
@ -185,6 +186,7 @@ static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API.";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated."; static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred."; static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* INVALID = "An invalid internal error occurred."; static constexpr const char* INVALID = "An invalid internal error occurred.";
const char* APIEvent::DescriptionForType(Type type) { const char* APIEvent::DescriptionForType(Type type) {
switch(type) { switch(type) {
// API Errors // API Errors
@ -345,6 +347,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return GETIFADDRS_ERROR; return GETIFADDRS_ERROR;
case Type::SendToError: case Type::SendToError:
return SEND_TO_ERROR; return SEND_TO_ERROR;
case Type::GPTPNotSupported:
return GPTP_NOT_SUPPORTED;
// FTD3XX // FTD3XX
case Type::FTOK: case Type::FTOK:

View File

@ -1,7 +1,18 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
set(PYBIND11_FINDPYTHON ON) set(PYBIND11_FINDPYTHON ON)
find_package(pybind11 CONFIG REQUIRED)
if(PYBIND11_ROOT)
find_package(pybind11 CONFIG REQUIRED)
else()
include(FetchContent)
FetchContent_Declare(
pybind11
GIT_REPOSITORY https://github.com/pybind/pybind11.git
GIT_TAG v2.13.6
)
FetchContent_MakeAvailable(pybind11)
endif()
pybind11_add_module(icsneopy pybind11_add_module(icsneopy
icsneopy/api/event.cpp icsneopy/api/event.cpp
@ -12,15 +23,29 @@ pybind11_add_module(icsneopy
icsneopy/communication/network.cpp icsneopy/communication/network.cpp
icsneopy/communication/message/message.cpp icsneopy/communication/message/message.cpp
icsneopy/communication/message/canmessage.cpp icsneopy/communication/message/canmessage.cpp
icsneopy/communication/message/canerrormessage.cpp
icsneopy/communication/message/ethernetmessage.cpp icsneopy/communication/message/ethernetmessage.cpp
icsneopy/communication/message/linmessage.cpp icsneopy/communication/message/linmessage.cpp
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/ethernetstatusmessage.cpp
icsneopy/communication/message/macsecmessage.cpp
icsneopy/communication/message/scriptstatusmessage.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/disk/diskdriver.cpp
icsneopy/device/device.cpp icsneopy/device/device.cpp
icsneopy/icsneocpp.cpp icsneopy/icsneocpp.cpp
) )
target_link_libraries(icsneopy PRIVATE icsneocpp) target_link_libraries(icsneopy PRIVATE icsneocpp)
install(TARGETS icsneopy LIBRARY DESTINATION .) install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN_EXE stubgen)
if(STUBGEN_EXE)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND stubgen -m icsneopy -o .)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi py.typed DESTINATION icsneopy)
endif()
install(FILES __init__.py DESTINATION icsneopy)

View File

@ -0,0 +1 @@
from .icsneopy import *

View File

@ -0,0 +1,38 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/canerrormessage.h"
namespace icsneo {
void init_errorcodes(pybind11::module_& m) {
pybind11::enum_<CANErrorCode>(m, "CANErrorCode")
.value("NoError", CANErrorCode::NoError)
.value("StuffError", CANErrorCode::StuffError)
.value("FormError", CANErrorCode::FormError)
.value("AckError", CANErrorCode::AckError)
.value("Bit1Error", CANErrorCode::Bit1Error)
.value("Bit0Error", CANErrorCode::Bit0Error)
.value("CRCError", CANErrorCode::CRCError)
.value("NoChange", CANErrorCode::NoChange);
}
void init_canerrormessage(pybind11::module_& m) {
init_errorcodes(m);
pybind11::class_<CANErrorMessage, std::shared_ptr<CANErrorMessage>, Message>(m, "CANErrorMessage")
.def_readonly("network", &CANErrorMessage::network)
.def_readonly("transmitErrorCount", &CANErrorMessage::transmitErrorCount)
.def_readonly("receiveErrorCount", &CANErrorMessage::receiveErrorCount)
.def_readonly("busOff", &CANErrorMessage::busOff)
.def_readonly("errorPassive", &CANErrorMessage::errorPassive)
.def_readonly("errorWarn", &CANErrorMessage::errorWarn)
.def_readonly("dataErrorCode", &CANErrorMessage::dataErrorCode)
.def_readonly("errorCode", &CANErrorMessage::errorCode);
m.attr("CANErrorCountMessage") = m.attr("CANErrorMessage");
}
} // namespace icsneo

View File

@ -15,7 +15,7 @@ void init_ethernetmessage(pybind11::module_& m) {
.def(pybind11::init()) .def(pybind11::init())
.def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled) .def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags) .def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)
.def_readwrite("fcsAvailable", &EthernetMessage::fcsAvailable) .def_readwrite("fcs", &EthernetMessage::fcs)
.def_readwrite("frameTooShort", &EthernetMessage::frameTooShort) .def_readwrite("frameTooShort", &EthernetMessage::frameTooShort)
.def_readwrite("noPadding", &EthernetMessage::noPadding) .def_readwrite("noPadding", &EthernetMessage::noPadding)
.def("get_destination_mac", &EthernetMessage::getDestinationMAC, pybind11::return_value_policy::reference) .def("get_destination_mac", &EthernetMessage::getDestinationMAC, pybind11::return_value_policy::reference)

View File

@ -0,0 +1,35 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/ethernetstatusmessage.h"
namespace icsneo {
void init_ethernetstatusmessage(pybind11::module_& m) {
pybind11::class_<EthernetStatusMessage, std::shared_ptr<EthernetStatusMessage>, Message> ethernetStatusMessage(m, "EthernetStatusMessage");
pybind11::enum_<EthernetStatusMessage::LinkSpeed>(ethernetStatusMessage, "LinkSpeed")
.value("LinkSpeedAuto", EthernetStatusMessage::LinkSpeed::LinkSpeedAuto)
.value("LinkSpeed10", EthernetStatusMessage::LinkSpeed::LinkSpeed10)
.value("LinkSpeed100", EthernetStatusMessage::LinkSpeed::LinkSpeed100)
.value("LinkSpeed1000", EthernetStatusMessage::LinkSpeed::LinkSpeed1000)
.value("LinkSpeed2500", EthernetStatusMessage::LinkSpeed::LinkSpeed2500)
.value("LinkSpeed5000", EthernetStatusMessage::LinkSpeed::LinkSpeed5000)
.value("LinkSpeed10000", EthernetStatusMessage::LinkSpeed::LinkSpeed10000);
pybind11::enum_<EthernetStatusMessage::LinkMode>(ethernetStatusMessage, "LinkMode")
.value("LinkModeAuto", EthernetStatusMessage::LinkMode::LinkModeAuto)
.value("LinkModeMaster", EthernetStatusMessage::LinkMode::LinkModeMaster)
.value("LinkModeSlave", EthernetStatusMessage::LinkMode::LinkModeSlave)
.value("LinkModeInvalid", EthernetStatusMessage::LinkMode::LinkModeInvalid);
ethernetStatusMessage
.def_readonly("network", &EthernetStatusMessage::network)
.def_readonly("state", &EthernetStatusMessage::state)
.def_readonly("speed", &EthernetStatusMessage::speed)
.def_readonly("duplex", &EthernetStatusMessage::duplex)
.def_readonly("mode", &EthernetStatusMessage::mode);
}
} // namespace icsneo

View File

@ -8,6 +8,8 @@ namespace icsneo {
void init_messagefilter(pybind11::module_& m) { void init_messagefilter(pybind11::module_& m) {
pybind11::class_<MessageFilter, std::shared_ptr<MessageFilter>>(m, "MessageFilter") pybind11::class_<MessageFilter, std::shared_ptr<MessageFilter>>(m, "MessageFilter")
.def(pybind11::init())
.def(pybind11::init<Message::Type>())
.def(pybind11::init<Network::NetID>()); .def(pybind11::init<Network::NetID>());
} }

View File

@ -0,0 +1,79 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/gptpstatusmessage.h"
namespace icsneo {
void init_gptpstatusmessage(pybind11::module_& m) {
pybind11::class_<GPTPStatus, std::shared_ptr<GPTPStatus>, Message> gptpStatus(m, "GPTPStatus");
pybind11::class_<GPTPStatus::Timestamp>(gptpStatus, "Timestamp")
.def_readonly("seconds", &GPTPStatus::Timestamp::seconds)
.def_readonly("nanoseconds", &GPTPStatus::Timestamp::nanoseconds)
.def("to_seconds", &GPTPStatus::Timestamp::toSeconds, pybind11::call_guard<pybind11::gil_scoped_release>());
pybind11::class_<GPTPStatus::ScaledNanoSeconds>(gptpStatus, "ScaledNanoSeconds")
.def_readonly("nanosecondsMSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsMSB)
.def_readonly("nanosecondsLSB", &GPTPStatus::ScaledNanoSeconds::nanosecondsLSB)
.def_readonly("fractionalNanoseconds", &GPTPStatus::ScaledNanoSeconds::fractionalNanoseconds);
pybind11::class_<GPTPStatus::PortID>(gptpStatus, "PortID")
.def_readonly("clockIdentity", &GPTPStatus::PortID::clockIdentity)
.def_readonly("portNumber", &GPTPStatus::PortID::portNumber);
pybind11::class_<GPTPStatus::ClockQuality>(gptpStatus, "ClockQuality")
.def_readonly("clockClass", &GPTPStatus::ClockQuality::clockClass)
.def_readonly("clockAccuracy", &GPTPStatus::ClockQuality::clockAccuracy)
.def_readonly("offsetScaledLogVariance", &GPTPStatus::ClockQuality::offsetScaledLogVariance);
pybind11::class_<GPTPStatus::SystemID>(gptpStatus, "SystemID")
.def_readonly("priority1", &GPTPStatus::SystemID::priority1)
.def_readonly("clockQuality", &GPTPStatus::SystemID::clockQuality)
.def_readonly("priority2", &GPTPStatus::SystemID::priority2)
.def_readonly("clockID", &GPTPStatus::SystemID::clockID);
pybind11::class_<GPTPStatus::PriorityVector>(gptpStatus, "PriorityVector")
.def_readonly("sysID", &GPTPStatus::PriorityVector::sysID)
.def_readonly("stepsRemoved", &GPTPStatus::PriorityVector::stepsRemoved)
.def_readonly("portID", &GPTPStatus::PriorityVector::portID)
.def_readonly("portNumber", &GPTPStatus::PriorityVector::portNumber);
pybind11::class_<GPTPStatus::ParentDS>(gptpStatus, "ParentDS")
.def_readonly("parentPortIdentity", &GPTPStatus::ParentDS::parentPortIdentity)
.def_readonly("cumulativeRateRatio", &GPTPStatus::ParentDS::cumulativeRateRatio)
.def_readonly("grandmasterIdentity", &GPTPStatus::ParentDS::grandmasterIdentity)
.def_readonly("gmClockQualityClockClass", &GPTPStatus::ParentDS::gmClockQualityClockClass)
.def_readonly("gmClockQualityClockAccuracy", &GPTPStatus::ParentDS::gmClockQualityClockAccuracy)
.def_readonly("gmClockQualityOffsetScaledLogVariance", &GPTPStatus::ParentDS::gmClockQualityOffsetScaledLogVariance)
.def_readonly("gmPriority1", &GPTPStatus::ParentDS::gmPriority1)
.def_readonly("gmPriority2", &GPTPStatus::ParentDS::gmPriority2);
pybind11::class_<GPTPStatus::CurrentDS>(gptpStatus, "CurrentDS")
.def_readonly("stepsRemoved", &GPTPStatus::CurrentDS::stepsRemoved)
.def_readonly("offsetFromMaster", &GPTPStatus::CurrentDS::offsetFromMaster)
.def_readonly("lastgmPhaseChange", &GPTPStatus::CurrentDS::lastgmPhaseChange)
.def_readonly("lastgmFreqChange", &GPTPStatus::CurrentDS::lastgmFreqChange)
.def_readonly("gmTimeBaseIndicator", &GPTPStatus::CurrentDS::gmTimeBaseIndicator)
.def_readonly("gmChangeCount", &GPTPStatus::CurrentDS::gmChangeCount)
.def_readonly("timeOfLastgmChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmChangeEvent)
.def_readonly("timeOfLastgmPhaseChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmPhaseChangeEvent)
.def_readonly("timeOfLastgmFreqChangeEvent", &GPTPStatus::CurrentDS::timeOfLastgmFreqChangeEvent);
gptpStatus.def_readonly("currentTime", &GPTPStatus::currentTime)
.def_readonly("gmPriority", &GPTPStatus::gmPriority)
.def_readonly("msOffsetNs", &GPTPStatus::msOffsetNs)
.def_readonly("isSync", &GPTPStatus::isSync)
.def_readonly("linkStatus", &GPTPStatus::linkStatus)
.def_readonly("linkDelayNS", &GPTPStatus::linkDelayNS)
.def_readonly("selectedRole", &GPTPStatus::selectedRole)
.def_readonly("asCapable", &GPTPStatus::asCapable)
.def_readonly("isSyntonized", &GPTPStatus::isSyntonized)
.def_readonly("lastRXSyncTS", &GPTPStatus::lastRXSyncTS)
.def_readonly("currentDS", &GPTPStatus::currentDS)
.def_readonly("parentDS", &GPTPStatus::parentDS);
}
} // namespace icsneo

View File

@ -0,0 +1,160 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/macsecmessage.h"
namespace icsneo {
void init_macsecmessage(pybind11::module_ & m)
{
pybind11::enum_<MACsecPacketType>(m, "MACsecPacketType")
.value("NoVLAN_OrMPLS", MACsecPacketType::NoVLANOrMPLS)
.value("SingleVLAN", MACsecPacketType::SingleVLAN)
.value("DualVLAN", MACsecPacketType::DualVLAN)
.value("MPLS", MACsecPacketType::MPLS)
.value("SingleVLAN_FollowByMPLS", MACsecPacketType::SingleVLANFollowedByMPLS)
.value("DualVLAN_FollowByMPLS", MACsecPacketType::DualVLANFollowedByMPLS)
.value("Unsupported", MACsecPacketType::Unsupported);
pybind11::enum_<MACsecValidateFrameType>(m, "MACsecValidateFrameType")
.value("Disabled", MACsecValidateFrameType::Disabled)
.value("Check", MACsecValidateFrameType::Check)
.value("Strict", MACsecValidateFrameType::Strict)
.value("NA", MACsecValidateFrameType::NA);
pybind11::enum_<MACsecSecTagIcvStripType>(m, "MACsecSecTagIcvStripType")
.value("StripBoth", MACsecSecTagIcvStripType::StripBoth)
.value("StripSecTagPreserveICV", MACsecSecTagIcvStripType::StripSecTagPreserveICV)
.value("PreserveSecTagStripICV", MACsecSecTagIcvStripType::PreserveSecTagStripICV)
.value("PreserveBoth", MACsecSecTagIcvStripType::PreserveBoth);
pybind11::enum_<MACsecCipherSuiteType>(m, "MACsecCipherSuiteType")
.value("AES_128", MACsecCipherSuiteType::GcmAes128)
.value("AES_256", MACsecCipherSuiteType::GcmAes256)
.value("AES_128_XPN", MACsecCipherSuiteType::GcmAes128Xpn)
.value("AES_256_XPN", MACsecCipherSuiteType::GcmAes256Xpn);
pybind11::class_<MACsecVLANTag, std::shared_ptr<MACsecVLANTag>>(m, "MACsecVLANTag")
.def(pybind11::init())
.def_readwrite("vid", &MACsecVLANTag::vid)
.def_readwrite("pri_cfi", &MACsecVLANTag::priCfi);
pybind11::class_<MACsecMPLSOuter, std::shared_ptr<MACsecMPLSOuter>>(m, "MACsecMPLSOuter")
.def(pybind11::init())
.def_readwrite("mpls_label", &MACsecMPLSOuter::mplsLabel)
.def_readwrite("exp", &MACsecMPLSOuter::exp);
pybind11::class_<MACsecRule, std::shared_ptr<MACsecRule>>(m, "MACsecRule")
.def(pybind11::init())
.def_readwrite("index", &MACsecRule::index)
.def_readwrite("keyMacDa", &MACsecRule::keyMacDa)
.def_readwrite("maskMacDa", &MACsecRule::maskMacDa)
.def_readwrite("keyMacSa", &MACsecRule::keyMacSa)
.def_readwrite("maskMacSa", &MACsecRule::maskMacSa)
.def_readwrite("keyEthertype", &MACsecRule::keyEthertype)
.def_readwrite("maskEthertype", &MACsecRule::maskEthertype)
.def_readwrite("keyVlanTagOuter1", &MACsecRule::keyVlanTagOuter1)
.def_readwrite("keyMplsOuter1", &MACsecRule::keyMplsOuter1)
.def_readwrite("maskVlanTagOuter1", &MACsecRule::maskVlanTagOuter1)
.def_readwrite("maskMplsOuter1", &MACsecRule::maskMplsOuter1)
.def_readwrite("keyVlanTagOuter2", &MACsecRule::keyVlanTagOuter2)
.def_readwrite("keyMplsOuter2", &MACsecRule::keyMplsOuter2)
.def_readwrite("maskVlanTagOuter2", &MACsecRule::maskVlanTagOuter2)
.def_readwrite("maskMplsOuter2", &MACsecRule::maskMplsOuter2)
.def_readwrite("keyBonusData", &MACsecRule::keyBonusData)
.def_readwrite("maskBonusData", &MACsecRule::maskBonusData)
.def_readwrite("keyTagMatchBitmap", &MACsecRule::keyTagMatchBitmap)
.def_readwrite("maskTagMatchBitmap", &MACsecRule::maskTagMatchBitmap)
.def_readwrite("keyPacketType", &MACsecRule::keyPacketType)
.def_readwrite("maskPacketType", &MACsecRule::maskPacketType)
.def_readwrite("keyInnerVlanType", &MACsecRule::keyInnerVlanType)
.def_readwrite("maskInnerVlanType", &MACsecRule::maskInnerVlanType)
.def_readwrite("keyOuterVlanType", &MACsecRule::keyOuterVlanType)
.def_readwrite("maskOuterVlanType", &MACsecRule::maskOuterVlanType)
.def_readwrite("keyNumTags", &MACsecRule::keyNumTags)
.def_readwrite("maskNumTags", &MACsecRule::maskNumTags)
.def_readwrite("keyExpress", &MACsecRule::keyExpress)
.def_readwrite("maskExpress", &MACsecRule::maskExpress)
.def_readwrite("isMpls", &MACsecRule::isMpls)
.def_readwrite("enable", &MACsecRule::enable);
pybind11::class_<MACsecMap, std::shared_ptr<MACsecMap>>(m, "MACsecMap")
.def(pybind11::init())
.def_readwrite("index", &MACsecMap::index)
.def_readwrite("secTagSci", &MACsecMap::secTagSci)
.def_readwrite("secYIndex", &MACsecMap::secYIndex)
.def_readwrite("isControlPacket", &MACsecMap::isControlPacket)
.def_readwrite("scIndex", &MACsecMap::scIndex)
.def_readwrite("auxiliaryPlcy", &MACsecMap::auxiliaryPlcy)
.def_readwrite("ruleId", &MACsecMap::ruleId)
.def_readwrite("enable", &MACsecMap::enable);
pybind11::class_<MACsecSecY, std::shared_ptr<MACsecSecY>>(m, "MACsecSecY")
.def(pybind11::init())
.def_readwrite("index", &MACsecSecY::index)
.def_readwrite("controlledPortEnabled", &MACsecSecY::controlledPortEnabled)
.def_readwrite("frameValidationType", &MACsecSecY::frameValidationType)
.def_readwrite("secTagIcvStripType", &MACsecSecY::secTagIcvStripType)
.def_readwrite("cipher", &MACsecSecY::cipher)
.def_readwrite("confidentialOffset", &MACsecSecY::confidentialOffset)
.def_readwrite("icvIncludesDaSa", &MACsecSecY::icvIncludesDaSa)
.def_readwrite("replayProtect", &MACsecSecY::replayProtect)
.def_readwrite("replayWindow", &MACsecSecY::replayWindow)
.def_readwrite("protectFrames", &MACsecSecY::protectFrames)
.def_readwrite("secTagOffset", &MACsecSecY::secTagOffset)
.def_readwrite("secTagTci", &MACsecSecY::secTagTci)
.def_readwrite("mtu", &MACsecSecY::mtu)
.def_readwrite("enable", &MACsecSecY::enable);
pybind11::class_<MACsecSc, std::shared_ptr<MACsecSc>>(m, "MACsecSc")
.def(pybind11::init())
.def_readwrite("index", &MACsecSc::index)
.def_readwrite("secYIndex", &MACsecSc::secYIndex)
.def_readwrite("sci", &MACsecSc::sci)
.def_readwrite("saIndex0", &MACsecSc::saIndex0)
.def_readwrite("saIndex1", &MACsecSc::saIndex1)
.def_readwrite("saIndex0InUse", &MACsecSc::saIndex0InUse)
.def_readwrite("saIndex1InUse", &MACsecSc::saIndex1InUse)
.def_readwrite("enableAutoRekey", &MACsecSc::enableAutoRekey)
.def_readwrite("isActiveSa1", &MACsecSc::isActiveSa1)
.def_readwrite("enable", &MACsecSc::enable);
pybind11::class_<MACsecSa, std::shared_ptr<MACsecSa>>(m, "MACsecSa")
.def(pybind11::init())
.def_readwrite("index", &MACsecSa::index)
.def_readwrite("sak", &MACsecSa::sak)
.def_readwrite("hashKey", &MACsecSa::hashKey)
.def_readwrite("salt", &MACsecSa::salt)
.def_readwrite("ssci", &MACsecSa::ssci)
.def_readwrite("an", &MACsecSa::an)
.def_readwrite("nextPn", &MACsecSa::nextPn)
.def_readwrite("enable", &MACsecSa::enable);
pybind11::class_<MACSecFlags, std::shared_ptr<MACSecFlags>>(m, "MACSecFlags")
.def(pybind11::init())
.def_readwrite("en", &MACSecFlags::en);
pybind11::class_<MACsecConfig, std::shared_ptr<MACsecConfig>>(m, "MACsecConfig")
.def(pybind11::init())
.def_readwrite("flags", &MACsecConfig::flags)
.def_readwrite("rule", &MACsecConfig::rule)
.def_readwrite("map", &MACsecConfig::map)
.def_readwrite("secy", &MACsecConfig::secy)
.def_readwrite("sc", &MACsecConfig::sc)
.def_readwrite("sa", &MACsecConfig::sa);
pybind11::class_<MACSecGlobalFlags, std::shared_ptr<MACSecGlobalFlags>>(m, "MACSecGlobalFlags")
.def(pybind11::init())
.def_readwrite("en", &MACSecGlobalFlags::en)
.def_readwrite("nvm", &MACSecGlobalFlags::nvm);
pybind11::class_<MACsecMessage, std::shared_ptr<MACsecMessage>>(m, "MACsecMessage")
.def(pybind11::init())
.def_readwrite("flags", &MACsecMessage::flags)
.def_readwrite("rx", &MACsecMessage::rx)
.def_readwrite("tx", &MACsecMessage::tx);
}
} // namespace icsneo

View File

@ -11,6 +11,7 @@ void init_message(pybind11::module_& m) {
pybind11::enum_<Message::Type>(message, "Type") pybind11::enum_<Message::Type>(message, "Type")
.value("Frame", Message::Type::Frame) .value("Frame", Message::Type::Frame)
.value("CANErrorCount", Message::Type::CANErrorCount) .value("CANErrorCount", Message::Type::CANErrorCount)
.value("CANError", Message::Type::CANError)
.value("LINHeaderOnly", Message::Type::LINHeaderOnly) .value("LINHeaderOnly", Message::Type::LINHeaderOnly)
.value("LINBreak", Message::Type::LINBreak) .value("LINBreak", Message::Type::LINBreak)
.value("Invalid", Message::Type::Invalid) .value("Invalid", Message::Type::Invalid)
@ -31,7 +32,9 @@ void init_message(pybind11::module_& m) {
.value("LiveData", Message::Type::LiveData) .value("LiveData", Message::Type::LiveData)
.value("HardwareInfo", Message::Type::HardwareInfo) .value("HardwareInfo", Message::Type::HardwareInfo)
.value("TC10Status", Message::Type::TC10Status) .value("TC10Status", Message::Type::TC10Status)
.value("AppError", Message::Type::AppError); .value("AppError", Message::Type::AppError)
.value("GPTPStatus", Message::Type::GPTPStatus)
.value("EthernetStatus", Message::Type::EthernetStatus);
message.def(pybind11::init<Message::Type>()); message.def(pybind11::init<Message::Type>());
message.def_readonly("type", &Message::type); message.def_readonly("type", &Message::type);

View File

@ -0,0 +1,30 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/communication/message/scriptstatusmessage.h"
namespace icsneo {
void init_scriptstatusmessage(pybind11::module_& m) {
pybind11::class_<ScriptStatusMessage, std::shared_ptr<ScriptStatusMessage>, Message>(m, "ScriptStatusMessage")
.def_readonly("isEncrypted", &ScriptStatusMessage::isEncrypted)
.def_readonly("isCoreminiRunning", &ScriptStatusMessage::isCoreminiRunning)
.def_readonly("sectorOverflows", &ScriptStatusMessage::sectorOverflows)
.def_readonly("numRemainingSectorBuffers", &ScriptStatusMessage::numRemainingSectorBuffers)
.def_readonly("lastSector", &ScriptStatusMessage::lastSector)
.def_readonly("readBinSize", &ScriptStatusMessage::readBinSize)
.def_readonly("minSector", &ScriptStatusMessage::minSector)
.def_readonly("maxSector", &ScriptStatusMessage::maxSector)
.def_readonly("currentSector", &ScriptStatusMessage::currentSector)
.def_readonly("coreminiCreateTime", &ScriptStatusMessage::coreminiCreateTime)
.def_readonly("fileChecksum", &ScriptStatusMessage::fileChecksum)
.def_readonly("coreminiVersion", &ScriptStatusMessage::coreminiVersion)
.def_readonly("coreminiHeaderSize", &ScriptStatusMessage::coreminiHeaderSize)
.def_readonly("diagnosticErrorCode", &ScriptStatusMessage::diagnosticErrorCode)
.def_readonly("diagnosticErrorCodeCount", &ScriptStatusMessage::diagnosticErrorCodeCount)
.def_readonly("maxCoreminiSizeKB", &ScriptStatusMessage::maxCoreminiSizeKB);
}
} // namespace icsneo

View File

@ -5,40 +5,51 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include <fstream>
namespace icsneo { namespace icsneo {
void init_device(pybind11::module_& m) { void init_device(pybind11::module_& m) {
pybind11::class_<Device, std::shared_ptr<Device>>(m, "Device") pybind11::class_<Device, std::shared_ptr<Device>>(m, "Device")
.def("get_type", &Device::getType) .def("__repr__", &Device::describe)
.def("get_serial", &Device::getSerial) .def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_serial_number", &Device::getSerialNumber) .def("clear_script", &Device::clearScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_product_name", &Device::getProductName) .def("close", &Device::close, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("open", [](Device& device) { return device.open(); }) .def("describe", &Device::describe)
.def("close", &Device::close) .def("disable_message_polling", &Device::disableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_open", &Device::isOpen) .def("enable_message_polling", &Device::enableMessagePolling, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("go_online", &Device::goOnline)
.def("go_offline", &Device::goOffline)
.def("is_online", &Device::isOnline).def("enable_message_polling", &Device::enableMessagePolling)
.def("disable_message_polling", &Device::disableMessagePolling)
.def("is_message_polling_enabled", &Device::isMessagePollingEnabled)
.def("get_messages", [](Device& device) { return device.getMessages(); })
.def("get_current_message_count", &Device::getCurrentMessageCount) .def("get_current_message_count", &Device::getCurrentMessageCount)
.def("get_gptp_status", &Device::getGPTPStatus, pybind11::arg("timeout") = std::chrono::milliseconds(100), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_messages", [](Device& device) { return device.getMessages(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_polling_message_limit", &Device::getPollingMessageLimit) .def("get_polling_message_limit", &Device::getPollingMessageLimit)
.def("set_polling_message_limit", &Device::setPollingMessageLimit) .def("get_product_name", &Device::getProductName)
.def("add_message_callback", &Device::addMessageCallback) .def("get_rtc", &Device::getRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("remove_message_callback", &Device::removeMessageCallback) .def("get_script_status", &Device::getScriptStatus, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit)) .def("get_serial_number", &Device::getSerialNumber)
.def("get_serial", &Device::getSerial)
.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_rtc", &Device::getRTC) .def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_rtc", &Device::setRTC) .def("get_type", &Device::getType)
.def("describe", &Device::describe) .def("go_offline", &Device::goOffline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("go_online", &Device::goOnline, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("is_message_polling_enabled", &Device::isMessagePollingEnabled)
.def("is_online_supported", &Device::isOnlineSupported) .def("is_online_supported", &Device::isOnlineSupported)
.def("is_online", &Device::isOnline)
.def("is_open", &Device::isOpen)
.def("open", [](Device& device) { return device.open(); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("prepare_script_load", &Device::prepareScriptLoad, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("remove_message_callback", &Device::removeMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_sleep", &Device::requestTC10Sleep, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_wake", &Device::requestTC10Wake, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("set_rtc", &Device::setRTC, 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("supports_tc10", &Device::supportsTC10) .def("supports_tc10", &Device::supportsTC10)
.def("request_tc10_wake", &Device::requestTC10Wake) .def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("request_tc10_sleep", &Device::requestTC10Sleep) .def("upload_coremini", [](Device& device, std::string& path, Disk::MemoryType memType) { std::ifstream ifs(path, std::ios::binary); return device.uploadCoremini(ifs, memType); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_tc10_status", &Device::getTC10Status) .def("write_macsec_config", &Device::writeMACsecConfig, pybind11::call_guard<pybind11::gil_scoped_release>());
.def("__repr__", &Device::describe);
} }
} // namespace icsneo } // namespace icsneo

View File

@ -0,0 +1,20 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/functional.h>
#include "icsneo/disk/diskdriver.h"
namespace icsneo {
void init_diskdriver(pybind11::module_& m) {
auto disk = m.def_submodule("disk");
pybind11::enum_<Disk::Access>(disk, "Access")
.value("None", Disk::Access::None)
.value("EntireCard", Disk::Access::EntireCard)
.value("VSA", Disk::Access::VSA);
pybind11::enum_<Disk::MemoryType>(disk, "MemoryType")
.value("Flash", Disk::MemoryType::Flash)
.value("SD", Disk::MemoryType::SD);
}
} // namespace icsneo

View File

@ -13,16 +13,24 @@ void init_network(pybind11::module_&);
void init_devicetype(pybind11::module_&); void init_devicetype(pybind11::module_&);
void init_message(pybind11::module_&); void init_message(pybind11::module_&);
void init_canmessage(pybind11::module_&); void init_canmessage(pybind11::module_&);
void init_canerrormessage(pybind11::module_&);
void init_ethernetmessage(pybind11::module_&); 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_mdiomessage(pybind11::module_&); void init_mdiomessage(pybind11::module_&);
void init_ethernetstatusmessage(pybind11::module_&);
void init_macsecmessage(pybind11::module_&);
void init_scriptstatusmessage(pybind11::module_&);
void init_diskdriver(pybind11::module_&);
void init_device(pybind11::module_&); void init_device(pybind11::module_&);
void init_messagefilter(pybind11::module_&); void init_messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&); void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&); void init_version(pybind11::module_&);
PYBIND11_MODULE(icsneopy, m) { PYBIND11_MODULE(icsneopy, m) {
pybind11::options options;
options.disable_enum_members_docstring();
m.doc() = "libicsneo Python module"; m.doc() = "libicsneo Python module";
init_event(m); init_event(m);
@ -33,12 +41,18 @@ PYBIND11_MODULE(icsneopy, m) {
init_network(m); init_network(m);
init_message(m); init_message(m);
init_canmessage(m); init_canmessage(m);
init_canerrormessage(m);
init_ethernetmessage(m); init_ethernetmessage(m);
init_linmessage(m); init_linmessage(m);
init_tc10statusmessage(m); init_tc10statusmessage(m);
init_gptpstatusmessage(m);
init_mdiomessage(m); init_mdiomessage(m);
init_ethernetstatusmessage(m);
init_macsecmessage(m);
init_scriptstatusmessage(m);
init_messagefilter(m); init_messagefilter(m);
init_messagecallback(m); init_messagecallback(m);
init_diskdriver(m);
init_device(m); init_device(m);
m.def("find_all_devices", &FindAllDevices); m.def("find_all_devices", &FindAllDevices);

View File

View File

@ -1,7 +1,7 @@
#!/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_BUILD_SYSTEM_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

View File

@ -6,7 +6,7 @@ REM build
cd build cd build
set CFLAGS=/WX set CFLAGS=/WX
set CXXFLAGS=/WX set CXXFLAGS=/WX
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_BUILD_SYSTEM_TESTS=ON -DLIBICSNEO_ENABLE_TCP=ON .. cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=ON ..
if %errorlevel% neq 0 exit /b %errorlevel% if %errorlevel% neq 0 exit /b %errorlevel%
cmake --build . cmake --build .
if %errorlevel% neq 0 exit /b %errorlevel% if %errorlevel% neq 0 exit /b %errorlevel%

View File

@ -1,2 +1,2 @@
call "%VCVARS32%" call "%VCVARS32_2022%"
call "ci\build-windows.bat" call "ci\build-windows.bat"

View File

@ -1,2 +1,2 @@
call "%VCVARS64%" call "%VCVARS64_2022%"
call "ci\build-windows.bat" call "ci\build-windows.bat"

View File

@ -37,29 +37,28 @@ bool Communication::open() {
} }
void Communication::spawnThreads() { void Communication::spawnThreads() {
closing = false;
readTaskThread = std::thread(&Communication::readTask, this); readTaskThread = std::thread(&Communication::readTask, this);
} }
void Communication::joinThreads() { void Communication::joinThreads() {
closing = true;
if(pauseReadTask) { if(pauseReadTask) {
resumeReads(); resumeReads();
} }
closing = true;
if(readTaskThread.joinable()) if(readTaskThread.joinable())
readTaskThread.join(); readTaskThread.join();
closing = false;
} }
bool Communication::close() { bool Communication::close() {
joinThreads();
if(!isOpen() && !isDisconnected()) { if(!isOpen() && !isDisconnected()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false; return false;
} }
joinThreads();
return driver->close(); return driver->close();
} }

View File

@ -0,0 +1,69 @@
/*
* crc32.c
*
* Created on: Jun 22, 2020
* Author: BJones
*/
#include "icsneo/communication/crc32.h"
static const unsigned long crc32_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F,
0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180,
0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2,
0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E,
0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9,
0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226,
0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E,
0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D };
uint32_t crc32(uint32_t crc, const unsigned char* buf, uint32_t len)
{
unsigned char octet;
const unsigned char* p = buf;
crc = ~crc;
while (len--)
{
octet = *p++; /* Cast to unsigned octet. */
crc = (crc >> 8) ^ crc32_table[(crc & 0xff) ^ octet];
}
return ~crc;
}
static unsigned char rev_crc32_table[256];
static void revgen(void)
{
unsigned char k;
for (k = 0; k < 256; k++)
rev_crc32_table[crc32_table[k] >> 24] = k;
}
uint32_t revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len)
{
unsigned char k;
revgen();
crc = ~crc;
while (len--)
{
k = rev_crc32_table[crc >> 24];
crc = ((crc ^ crc32_table[k]) << 8) | (k ^ buf[len]);
}
return ~crc;
}

View File

@ -3,7 +3,7 @@
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h" #include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flashmemorymessage.h" #include "icsneo/communication/message/flashmemorymessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h" #include "icsneo/communication/message/extendedresponsemessage.h"
@ -19,7 +19,9 @@
#include "icsneo/communication/message/diskdatamessage.h" #include "icsneo/communication/message/diskdatamessage.h"
#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/apperrormessage.h" #include "icsneo/communication/message/apperrormessage.h"
#include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
@ -93,7 +95,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
break; break;
} }
case Message::Type::CANErrorCount: { case Message::Type::CANErrorCount: {
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get()); CANErrorMessage& can = *static_cast<CANErrorMessage*>(result.get());
can.network = packet->network; can.network = packet->network;
break; break;
} }
@ -178,6 +180,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
LINMessage& msg = *static_cast<LINMessage*>(result.get()); LINMessage& msg = *static_cast<LINMessage*>(result.get());
msg.network = packet->network; msg.network = packet->network;
msg.timestamp *= timestampResolution;
return true; return true;
} }
case Network::Type::MDIO: { case Network::Type::MDIO: {
@ -236,21 +239,26 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true; return true;
} }
result = HardwareCANPacket::DecodeToMessage(packet->data); const auto can = std::dynamic_pointer_cast<CANMessage>(HardwareCANPacket::DecodeToMessage(packet->data));
if(!result) { if(!can) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false;
}
if(can->arbid == 0x162) {
result = EthernetStatusMessage::DecodeToMessage(can->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
} else {
// TODO: move more handleNeoVIMessage handling here, the Decoder layer will parse the message and the Device layer can cache the values
can->network = packet->network;
result = can;
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 result->timestamp *= timestampResolution;
// The resolution depends on the device
auto* raw = dynamic_cast<RawMessage*>(result.get());
if(raw == nullptr) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
raw->timestamp *= timestampResolution;
raw->network = packet->network;
return true; return true;
} }
case Network::NetID::DeviceStatus: { case Network::NetID::DeviceStatus: {
@ -284,11 +292,11 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
case Network::NetID::ExtendedCommand: { case Network::NetID::ExtendedCommand: {
if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse)) if(packet->data.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
break; // Handle as a raw message, might not be a generic response break; // Handle as a raw message, might not be a generic response
const auto& resp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data()); const auto& resp = *reinterpret_cast<ExtendedResponseMessage::ResponseHeader*>(packet->data.data());
switch(resp.header.command) { switch(resp.command) {
case ExtendedCommand::GetComponentVersions: case ExtendedCommand::GetComponentVersions:
result = ComponentVersionPacket::DecodeToMessage(packet->data); result = ComponentVersionPacket::DecodeToMessage(packet->data);
return true; return true;
@ -298,15 +306,23 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::GenericBinaryInfo: case ExtendedCommand::GenericBinaryInfo:
result = GenericBinaryStatusPacket::DecodeToMessage(packet->data); result = GenericBinaryStatusPacket::DecodeToMessage(packet->data);
return true; return true;
case ExtendedCommand::GenericReturn: case ExtendedCommand::GenericReturn: {
result = std::make_shared<ExtendedResponseMessage>(resp.command, resp.returnCode); if(packet->data.size() < sizeof(ExtendedResponseMessage::PackedGenericResponse))
break;
const auto& packedResp = *reinterpret_cast<ExtendedResponseMessage::PackedGenericResponse*>(packet->data.data());
result = std::make_shared<ExtendedResponseMessage>(packedResp.command, packedResp.returnCode);
return true; return true;
}
case ExtendedCommand::LiveData: case ExtendedCommand::LiveData:
result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report); result = HardwareLiveDataPacket::DecodeToMessage(packet->data, report);
return true; return true;
case ExtendedCommand::GetTC10Status: case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data); result = TC10StatusMessage::DecodeToMessage(packet->data);
return true; return true;
case ExtendedCommand::GetGPTPStatus: {
result = GPTPStatus::DecodeToMessage(packet->data, report);
return true;
}
default: default:
// No defined handler, treat this as a RawMessage // No defined handler, treat this as a RawMessage
break; break;

View File

@ -265,6 +265,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
case Command::GetMainVersion: case Command::GetMainVersion:
case Command::GetSecondaryVersions: case Command::GetSecondaryVersions:
case Command::NeoReadMemory: case Command::NeoReadMemory:
case Command::ClearCoreMini:
case Command::LoadCoreMini:
// There is a firmware handling idiosyncrasy with these commands // There is a firmware handling idiosyncrasy with these commands
// They must be encoded in the short format // They must be encoded in the short format
m51msg->forceShortFormat = true; m51msg->forceShortFormat = true;

View File

@ -0,0 +1,57 @@
#include "icsneo/communication/message/ethernetstatusmessage.h"
using namespace icsneo;
#pragma pack(push, 1)
enum LinkSpeed {
ethSpeed10,
ethSpeed100,
ethSpeed1000,
ethSpeedAutoNeg,
ethSpeed2500,
ethSpeed5000,
ethSpeed10000,
};
enum LinkMode {
OPETH_LINK_AUTO,
OPETH_LINK_MASTER,
OPETH_LINK_SLAVE,
OPETH_LINK_INVALID = 255,
};
struct Packet {
uint8_t state;
uint8_t speed;
uint8_t duplex;
uint16_t network;
uint8_t mode;
};
#pragma pack(pop)
std::shared_ptr<Message> EthernetStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(Packet)) {
return nullptr;
}
Packet* packet = (Packet*)bytestream.data();
LinkSpeed speed;
switch(packet->speed) {
case ethSpeed10: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed10; break;
case ethSpeed100: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed100; break;
case ethSpeed1000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed1000; break;
case ethSpeedAutoNeg: speed = EthernetStatusMessage::LinkSpeed::LinkSpeedAuto; break;
case ethSpeed2500: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed2500; break;
case ethSpeed5000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed5000; break;
case ethSpeed10000: speed = EthernetStatusMessage::LinkSpeed::LinkSpeed10000; break;
default: return nullptr;
}
LinkMode mode;
switch(packet->mode) {
case OPETH_LINK_INVALID: mode = EthernetStatusMessage::LinkMode::LinkModeInvalid; break;
case OPETH_LINK_AUTO: mode = EthernetStatusMessage::LinkMode::LinkModeAuto; break;
case OPETH_LINK_MASTER: mode = EthernetStatusMessage::LinkMode::LinkModeMaster; break;
case OPETH_LINK_SLAVE: mode = EthernetStatusMessage::LinkMode::LinkModeSlave; break;
default: return nullptr;
}
return std::make_shared<EthernetStatusMessage>(packet->network, packet->state, speed, packet->duplex, mode);
}

View File

@ -0,0 +1,219 @@
#include <icsneo/communication/message/gptpstatusmessage.h>
#include <icsneo/communication/message/extendedresponsemessage.h>
#include <cstring>
namespace icsneo {
typedef double float64;
typedef int64_t time_interval;
typedef uint64_t _clock_identity;
#pragma pack(push, 1)
struct port_identity {
_clock_identity clock_identity;
uint16_t port_number;
};
struct _scaled_ns {
int16_t nanoseconds_msb;
int64_t nanoseconds_lsb;
int16_t fractional_nanoseconds;
};
struct _clock_quality {
uint8_t clock_class;
uint8_t clock_accuracy;
uint16_t offset_scaled_log_variance;
};
struct system_identity {
uint8_t priority_1;
struct _clock_quality clock_quality;
uint8_t priority_2;
_clock_identity clock_identity;
};
struct _timestamp {
uint16_t seconds_msb;
uint32_t seconds_lsb;
uint32_t nanoseconds;
};
struct priority_vector {
struct system_identity sysid;
uint16_t steps_removed;
struct port_identity portid;
uint16_t port_number;
};
// IEEE 802.1AS-2020 14.3
// This is a read-only data structure
struct _current_ds {
uint16_t steps_removed;
time_interval offset_from_master;
struct _scaled_ns last_gm_phase_change;
float64 last_gm_freq_change;
uint16_t gm_time_base_indicator;
uint32_t gm_change_count;
uint32_t time_of_last_gm_change_event;
uint32_t time_of_last_gm_phase_change_event;
uint32_t time_of_last_gm_freq_change_event;
};
// IEEE 802.1AS-2020 14.4
// This is a read-only data structure
struct _parent_ds {
struct port_identity parent_port_identity;
int32_t cumulative_rate_ratio;
_clock_identity grandmaster_identity;
uint8_t gm_clock_quality_clock_class;
uint8_t gm_clock_quality_clock_accuracy;
uint16_t gm_clock_quality_offset_scaled_log_variance;
uint8_t gm_priority1;
uint8_t gm_priority2;
};
struct _GPTPStatus
{
struct _timestamp current_time;
struct priority_vector gm_priority;
int64_t ms_offset_ns;
uint8_t is_sync;
uint8_t link_status;
int64_t link_delay_ns;
uint8_t selected_role;
uint8_t as_capable;
uint8_t is_syntonized;
struct _timestamp last_rx_sync_ts; // t2 in IEEE 1588-2019 Figure-16
struct _current_ds current_ds;
struct _parent_ds parent_ds;
};
#pragma pack(pop)
static void SetField(GPTPStatus::Timestamp& output, const _timestamp& input) {
output.seconds = ((uint64_t)(input.seconds_msb) << 32) | ((uint64_t)input.seconds_lsb);
output.nanoseconds = input.nanoseconds;
}
static void SetField(GPTPStatus::PortID& output, const port_identity& input) {
output.clockIdentity = input.clock_identity;
output.portNumber = input.port_number;
}
static void SetField(GPTPStatus::ClockQuality& output, const _clock_quality& input) {
output.clockClass = input.clock_class;
output.clockAccuracy = input.clock_accuracy;
output.offsetScaledLogVariance = input.offset_scaled_log_variance;
}
static void SetField(GPTPStatus::SystemID& output, const system_identity& input) {
output.priority1 = input.priority_1;
SetField(output.clockQuality, input.clock_quality);
output.priority2 = input.priority_2;
output.clockID = input.clock_identity;
}
static void SetField(GPTPStatus::ScaledNanoSeconds& output, const _scaled_ns& input) {
output.nanosecondsMSB = input.nanoseconds_msb;
output.nanosecondsLSB = input.nanoseconds_lsb;
output.fractionalNanoseconds = input.fractional_nanoseconds;
}
static void SetField(GPTPStatus::PriorityVector& output, const priority_vector& input) {
SetField(output.sysID, input.sysid);
output.stepsRemoved = input.steps_removed;
SetField(output.portID, input.portid);
output.portNumber = input.port_number;
}
static void SetField(GPTPStatus::CurrentDS& output, const _current_ds& input) {
output.stepsRemoved = input.steps_removed;
output.offsetFromMaster = input.offset_from_master;
SetField(output.lastgmPhaseChange, input.last_gm_phase_change);
output.lastgmFreqChange = input.last_gm_freq_change;
output.gmTimeBaseIndicator = input.gm_time_base_indicator;
output.gmChangeCount = input.gm_change_count;
output.timeOfLastgmChangeEvent = input.time_of_last_gm_change_event;
output.timeOfLastgmPhaseChangeEvent = input.time_of_last_gm_phase_change_event;
output.timeOfLastgmFreqChangeEvent = input.time_of_last_gm_freq_change_event;
}
static void SetField(GPTPStatus::ParentDS& output, const _parent_ds& input) {
SetField(output.parentPortIdentity, input.parent_port_identity);
output.cumulativeRateRatio = input.cumulative_rate_ratio;
output.grandmasterIdentity = input.grandmaster_identity;
output.gmClockQualityClockClass = input.gm_clock_quality_clock_class;
output.gmClockQualityClockAccuracy = input.gm_clock_quality_clock_accuracy;
output.gmClockQualityOffsetScaledLogVariance = input.gm_clock_quality_offset_scaled_log_variance;
output.gmPriority1 = input.gm_priority1;
output.gmPriority2 = input.gm_priority2;
}
[[maybe_unused]] static void SetField(uint8_t& output, const uint8_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint16_t& output, const uint16_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint32_t& output, const uint32_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(uint64_t& output, const uint64_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int8_t& output, const int8_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int16_t& output, const int16_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int32_t& output, const int32_t& input) {
output = input;
}
[[maybe_unused]] static void SetField(int64_t& output, const int64_t& input) {
output = input;
}
std::shared_ptr<GPTPStatus> GPTPStatus::DecodeToMessage(std::vector<uint8_t>& bytes, const device_eventhandler_t&) {
// The following does not lead to overflow since we only call this function if it has at least ResponseHeader length bytes
std::shared_ptr<GPTPStatus> res = std::make_shared<GPTPStatus>();
auto* header = reinterpret_cast<ExtendedResponseMessage::ResponseHeader*>(bytes.data());
uint16_t length = header->length;
_GPTPStatus* input = reinterpret_cast<_GPTPStatus*>(bytes.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
#define CheckLengthAndSet(output, input) if(length >= sizeof(decltype(input))) { \
SetField(output, input); \
length -= sizeof(decltype(input)); \
} else {\
memset(&output, 0, sizeof(decltype(output))); \
length = 0; \
res->shortFormat = true; \
}
CheckLengthAndSet(res->currentTime, input->current_time);
CheckLengthAndSet(res->gmPriority, input->gm_priority);
CheckLengthAndSet(res->msOffsetNs, input->ms_offset_ns);
CheckLengthAndSet(res->isSync, input->is_sync);
CheckLengthAndSet(res->linkStatus, input->link_status);
CheckLengthAndSet(res->linkDelayNS, input->link_delay_ns);
CheckLengthAndSet(res->selectedRole, input->selected_role);
CheckLengthAndSet(res->asCapable, input->as_capable);
CheckLengthAndSet(res->isSyntonized, input->is_syntonized);
CheckLengthAndSet(res->lastRXSyncTS, input->last_rx_sync_ts);
CheckLengthAndSet(res->currentDS, input->current_ds);
CheckLengthAndSet(res->parentDS, input->parent_ds);
return res;
}
}

View File

@ -0,0 +1,531 @@
#include "icsneo/communication/message/macsecmessage.h"
#include "icsneo/communication/crc32.h"
#include <memory>
#include <cstdint>
#include <iostream>
#include <cstring>
namespace icsneo
{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#endif
#pragma pack(push, 1)
/* MACsec Rule */
/**
* @brief Structure of Vlan tag
*
*/
typedef struct
{
uint16_t vid; /*!< 12 bits */
uint8_t priCfi; /*!< PRI - 3 bits, CFI - 1bit */
} MACSEC_VLANTAG_t;
/**
* @brief Structure of MPLS
*
*/
typedef struct
{
uint32_t mplsLabel; /*!< 20 bits */
uint8_t exp; /*!< 3 bits */
} MACSEC_MPLS_OUTER_t;
/**
* @brief Define Encoded Packet Type from the parser
*
*/
static constexpr int MACSEC_SETTINGS_RULE_SIZE = 88;
typedef union _MACSecRule
{
struct
{
uint8_t index;
uint8_t keyMacDa[6]; /*!< MAC DA field extracted from the packet */
uint8_t maskMacDa[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyMacSa[6]; /*!< MAC SA field extracted from the packet */
uint8_t maskMacSa[6]; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyEthertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */
uint16_t maskEthertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_VLANTAG_t keyVlanTagOuter1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACSEC_MPLS_OUTER_t keyMplsOuter1;
MACSEC_VLANTAG_t maskVlanTagOuter1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_MPLS_OUTER_t maskMplsOuter1;
MACSEC_VLANTAG_t keyVlanTagOuter2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACSEC_MPLS_OUTER_t keyMplsOuter2;
MACSEC_VLANTAG_t maskVlanTagOuter2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACSEC_MPLS_OUTER_t maskMplsOuter2;
uint16_t keyBonusData; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */
uint16_t maskBonusData; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t
keyTagMatchBitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */
uint8_t maskTagMatchBitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyPacketType; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */
uint8_t maskPacketType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t
keyInnerVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */
uint16_t maskInnerVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyOuterVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */
uint16_t maskOuterVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t
keyNumTags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */
uint8_t maskNumTags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyExpress; /*!< 1 bits. Express packet. */
uint8_t maskExpress; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t isMpls;
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_RULE_SIZE];
} MACSecRule_t;
/* MACsec Map */
static constexpr int MACSEC_SETTINGS_MAP_SIZE = 20;
typedef union _MACSecMap
{
struct
{
uint8_t index;
uint64_t secTagSci; /*!< Identifies the SecTAG SCI for this Flow. */
uint8_t secYIndex; /*!< index for entry in Egress secY Policy */
uint8_t isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */
uint8_t scIndex; /*!< Identifies the SC for this Flow. */
uint8_t auxiliaryPlcy; /*!< Auxiliary policy bits. */
uint8_t ruleId; /*!< Identifies the Rule for this Flow. */
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_MAP_SIZE];
} MACSecMap_t;
/* MACsec SecY */
/**
* @brief Define the permit police for frames as defined in 802.1ae
*
*/
static constexpr int MACSEC_SETTINGS_SECY_SIZE = 24;
typedef union _MACSecSecY
{
struct
{
uint8_t index; /*!< Identifies the SecY for this Flow. */
uint8_t controlledPortEnabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */
uint8_t frameValidationType; /*!< see MACSEC_VALIDATEFRAME */
uint8_t secTagIcvStripType; /*!< see MACSEC_STRIP_SECTAG_ICV */
uint8_t cipher; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */
uint8_t confidentialOffset; /*!< Define the number of bytes that are unencrypted following the SecTag. */
uint8_t icvIncludesDaSa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */
uint8_t replayProtect; /*!< Enables Anti-Replay protection */
uint32_t replayWindow; /*!< Unsigned value indicating the size of the anti-replay window. */
uint8_t
protectFrames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */
uint8_t
secTagOffset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */
uint8_t secTagTci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */
uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */
uint8_t rsvd[6];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SECY_SIZE];
} MACSecSecY_t;
/* MACsec SC */
static constexpr int MACSEC_SETTINGS_SC_SIZE = 24;
typedef union _MACSecSc
{
struct
{
uint8_t index; /*!< SC index. */
uint8_t secYIndex; /*!< SecY associated with this packet. */
uint64_t sci; /*!< The Secure Channel Identifier. */
uint8_t saIndex0; /*!< Define the 1st SA to use */
uint8_t saIndex1; /*!< Define the 2nd SA to use */
uint8_t saIndex0InUse; /*!< Specifies whether 1st SA is in use or not. */
uint8_t saIndex1InUse; /*!< Specifies whether 2nd SA is in use or not. */
uint8_t enableAutoRekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */
uint8_t
isActiveSa1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */
uint8_t rsvd[7];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SC_SIZE];
} MACSecSc_t;
/* MACsec SA */
static constexpr int MACSEC_SETTINGS_SA_SIZE = 80;
typedef union _MACSecSa
{
struct
{
uint8_t index; /*!< SA index */
uint8_t
sak[32]; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */
uint8_t hashKey[16]; /*!< 128b Hash Key: Key used for authentication. */
uint8_t salt[12]; /*!< 96b Salt value: Salt value used in XPN ciphers. */
uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */
uint8_t an; /*!< 2b SecTag Association Number (AN) */
uint64_t nextPn; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */
uint8_t rsvd[5];
uint8_t enable;
};
uint8_t byte[MACSEC_SETTINGS_SA_SIZE];
} MACSecSa_t;
/* MACsec Flags */
static constexpr int MACSEC_SETTINGS_FLAGS_SIZE = 4;
typedef union _MACSecFlags
{
struct
{
uint32_t en : 1; // '1' = enable; '0' = disable
uint32_t reserved : 31;
};
uint32_t flags_32b;
} MACSecFlags_t;
/* MACSec Settings for 1 port/phy */
typedef struct MACSEC_CONFIG_t
{
MACSecFlags_t flags;
MACSecRule_t rule[MACsecConfig::NumRules];
MACSecMap_t map[MACsecConfig::NumMaps];
MACSecSecY_t secy[MACsecConfig::NumSecY];
MACSecSc_t sc[MACsecConfig::NumSc];
MACSecSa_t sa[MACsecConfig::NumSa];
} MACSEC_CONFIG;
typedef union _MACSecGlobalFlags
{
struct
{
uint32_t en : 1; // '1' = enable; '0' = disable
uint32_t nvm : 1; // store macsec config in non-volatile memory
uint32_t reserved : 30;
};
uint32_t flags_32b;
} MACSecGlobalFlags_t;
#define MACSEC_SETTINGS_SIZE (2040) // leave space for expansion and keep nicely aligned for flashing
typedef union _MACSEC_SETTINGS
{
struct
{
MACSecGlobalFlags_t flags;
MACSEC_CONFIG rx;
MACSEC_CONFIG tx;
};
uint8_t byte[MACSEC_SETTINGS_SIZE];
} MACSEC_SETTINGS;
#define MACSEC_SETTINGS_VERSION 1
struct MACSEC_SETTINGS_W_HDR
{
uint16_t version;
uint16_t len;
uint32_t crc32;
MACSEC_SETTINGS macsec;
};
#pragma pack(pop)
#ifdef _MSC_VER
#pragma warning(pop)
#endif
std::shared_ptr<MACsecMessage> MACsecMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
if (bytestream.empty() || (bytestream.size() < sizeof(MACSEC_SETTINGS_W_HDR)))
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
MACSEC_SETTINGS_W_HDR* macsecArgs = (MACSEC_SETTINGS_W_HDR*)bytestream.data();
if (macsecArgs->version != MACSEC_SETTINGS_VERSION)
{
report(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
return nullptr;
}
if (macsecArgs->len != sizeof(MACSEC_SETTINGS))
{
report(APIEvent::Type::SettingsLengthError, APIEvent::Severity::Error);
return nullptr;
}
const auto crcCalculted = crc32(0, (uint8_t*)&macsecArgs->macsec, macsecArgs->len);
if (macsecArgs->crc32 != crcCalculted)
{
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return nullptr;
}
auto msg = std::make_shared<MACsecMessage>();
const auto& copyConfig = [](const MACSEC_CONFIG& source, MACsecConfig& dest)
{
dest.flags.en = source.flags.en;
for (int index = 0; index < MACsecConfig::NumRules; index++)
{
if(!source.rule[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.rule[index].___name__ = (decltype(dest.rule[index].___name__))source.rule[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.rule[index].___name__.data(), source.rule[index].___name__, dest.rule[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(keyMacDa);
__COPY_ARR(maskMacDa);
__COPY_ARR(keyMacSa);
__COPY_ARR(maskMacSa);
__COPY_ITEM(keyVlanTagOuter1.vid);
__COPY_ITEM(keyVlanTagOuter1.priCfi);
__COPY_ITEM(keyMplsOuter1.mplsLabel);
__COPY_ITEM(keyMplsOuter1.exp);
__COPY_ITEM(maskVlanTagOuter1.vid);
__COPY_ITEM(maskVlanTagOuter1.priCfi);
__COPY_ITEM(maskMplsOuter1.mplsLabel);
__COPY_ITEM(maskMplsOuter1.exp);
__COPY_ITEM(keyVlanTagOuter2.vid);
__COPY_ITEM(keyVlanTagOuter2.priCfi);
__COPY_ITEM(keyMplsOuter2.mplsLabel);
__COPY_ITEM(keyMplsOuter2.exp);
__COPY_ITEM(maskVlanTagOuter2.vid);
__COPY_ITEM(maskVlanTagOuter2.priCfi);
__COPY_ITEM(maskMplsOuter2.mplsLabel);
__COPY_ITEM(maskMplsOuter2.exp);
__COPY_ITEM(keyEthertype);
__COPY_ITEM(maskEthertype);
__COPY_ITEM(keyBonusData);
__COPY_ITEM(maskBonusData);
__COPY_ITEM(keyTagMatchBitmap);
__COPY_ITEM(maskTagMatchBitmap);
__COPY_ITEM(keyPacketType);
__COPY_ITEM(maskPacketType);
__COPY_ITEM(keyInnerVlanType);
__COPY_ITEM(maskInnerVlanType);
__COPY_ITEM(keyOuterVlanType);
__COPY_ITEM(maskOuterVlanType);
__COPY_ITEM(keyNumTags);
__COPY_ITEM(maskNumTags);
__COPY_ITEM(keyExpress);
__COPY_ITEM(maskExpress);
__COPY_ITEM(isMpls);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumMaps; index++)
{
if(!source.map[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.map[index].___name__ = source.map[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secTagSci);
__COPY_ITEM(secYIndex);
__COPY_ITEM(isControlPacket);
__COPY_ITEM(scIndex);
__COPY_ITEM(auxiliaryPlcy);
__COPY_ITEM(ruleId);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSecY; index++)
{
if(!source.secy[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.secy[index].___name__ = (decltype(dest.secy[index].___name__))source.secy[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(controlledPortEnabled);
__COPY_ITEM(frameValidationType);
__COPY_ITEM(secTagIcvStripType);
__COPY_ITEM(cipher);
__COPY_ITEM(confidentialOffset);
__COPY_ITEM(icvIncludesDaSa);
__COPY_ITEM(replayProtect);
__COPY_ITEM(replayWindow);
__COPY_ITEM(protectFrames);
__COPY_ITEM(secTagOffset);
__COPY_ITEM(secTagTci);
__COPY_ITEM(mtu);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSc; index++)
{
if(!source.sc[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sc[index].___name__ = source.sc[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secYIndex);
__COPY_ITEM(sci);
__COPY_ITEM(saIndex0);
__COPY_ITEM(saIndex1);
__COPY_ITEM(saIndex0InUse);
__COPY_ITEM(saIndex1InUse);
__COPY_ITEM(enableAutoRekey);
__COPY_ITEM(isActiveSa1);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSa; index++)
{
if(!source.sa[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sa[index].___name__ = source.sa[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.sa[index].___name__.data(), source.sa[index].___name__, dest.sa[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(sak);
__COPY_ARR(hashKey);
__COPY_ARR(salt);
__COPY_ITEM(ssci);
__COPY_ITEM(an);
__COPY_ITEM(nextPn);
__COPY_ITEM(enable);
}
};
msg->flags.en = macsecArgs->macsec.flags.en;
copyConfig(macsecArgs->macsec.rx, msg->rx);
copyConfig(macsecArgs->macsec.tx, msg->tx);
return msg;
}
bool MACsecMessage::EncodeFromMessage(std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) const
{
MACSEC_SETTINGS_W_HDR* macsecArgs;
bytestream.resize(sizeof(MACSEC_SETTINGS_W_HDR), 0);
macsecArgs = (MACSEC_SETTINGS_W_HDR*)bytestream.data();
macsecArgs->version = MACSEC_SETTINGS_VERSION;
macsecArgs->len = sizeof(MACSEC_SETTINGS_W_HDR);
const auto& copyConfig = [](const MACsecConfig& source, MACSEC_CONFIG& dest)
{
dest.flags.en = (uint8_t)source.flags.en;
for (int index = 0; index < MACsecConfig::NumRules; index++)
{
if(!source.rule[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.rule[index].___name__ = (decltype(dest.rule[index].___name__))source.rule[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.rule[index].___name__, source.rule[index].___name__.data(), source.rule[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(keyMacDa);
__COPY_ARR(maskMacDa);
__COPY_ARR(keyMacSa);
__COPY_ARR(maskMacSa);
__COPY_ITEM(keyVlanTagOuter1.vid);
__COPY_ITEM(keyVlanTagOuter1.priCfi);
__COPY_ITEM(keyMplsOuter1.mplsLabel);
__COPY_ITEM(keyMplsOuter1.exp);
__COPY_ITEM(maskVlanTagOuter1.vid);
__COPY_ITEM(maskVlanTagOuter1.priCfi);
__COPY_ITEM(maskMplsOuter1.mplsLabel);
__COPY_ITEM(maskMplsOuter1.exp);
__COPY_ITEM(keyVlanTagOuter2.vid);
__COPY_ITEM(keyVlanTagOuter2.priCfi);
__COPY_ITEM(keyMplsOuter2.mplsLabel);
__COPY_ITEM(keyMplsOuter2.exp);
__COPY_ITEM(maskVlanTagOuter2.vid);
__COPY_ITEM(maskVlanTagOuter2.priCfi);
__COPY_ITEM(maskMplsOuter2.mplsLabel);
__COPY_ITEM(maskMplsOuter2.exp);
__COPY_ITEM(keyEthertype);
__COPY_ITEM(maskEthertype);
__COPY_ITEM(keyBonusData);
__COPY_ITEM(maskBonusData);
__COPY_ITEM(keyTagMatchBitmap);
__COPY_ITEM(maskTagMatchBitmap);
__COPY_ITEM(keyPacketType);
__COPY_ITEM(maskPacketType);
__COPY_ITEM(keyInnerVlanType);
__COPY_ITEM(maskInnerVlanType);
__COPY_ITEM(keyOuterVlanType);
__COPY_ITEM(maskOuterVlanType);
__COPY_ITEM(keyNumTags);
__COPY_ITEM(maskNumTags);
__COPY_ITEM(keyExpress);
__COPY_ITEM(maskExpress);
__COPY_ITEM(isMpls);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumMaps; index++)
{
if(!source.map[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.map[index].___name__ = source.map[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secTagSci);
__COPY_ITEM(secYIndex);
__COPY_ITEM(isControlPacket);
__COPY_ITEM(scIndex);
__COPY_ITEM(auxiliaryPlcy);
__COPY_ITEM(ruleId);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSecY; index++)
{
if(!source.secy[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.secy[index].___name__ = (decltype(dest.secy[index].___name__))source.secy[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(controlledPortEnabled);
__COPY_ITEM(frameValidationType);
__COPY_ITEM(secTagIcvStripType);
__COPY_ITEM(cipher);
__COPY_ITEM(confidentialOffset);
__COPY_ITEM(icvIncludesDaSa);
__COPY_ITEM(replayProtect);
__COPY_ITEM(replayWindow);
__COPY_ITEM(protectFrames);
__COPY_ITEM(secTagOffset);
__COPY_ITEM(secTagTci);
__COPY_ITEM(mtu);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSc; index++)
{
if(!source.sc[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sc[index].___name__ = source.sc[index].___name__
__COPY_ITEM(index);
__COPY_ITEM(secYIndex);
__COPY_ITEM(sci);
__COPY_ITEM(saIndex0);
__COPY_ITEM(saIndex1);
__COPY_ITEM(saIndex0InUse);
__COPY_ITEM(saIndex1InUse);
__COPY_ITEM(enableAutoRekey);
__COPY_ITEM(isActiveSa1);
__COPY_ITEM(enable);
}
for (int index = 0; index < MACsecConfig::NumSa; index++)
{
if(!source.sa[index].enable) continue;
#undef __COPY_ITEM
#define __COPY_ITEM(___name__) dest.sa[index].___name__ = source.sa[index].___name__
#undef __COPY_ARR
#define __COPY_ARR(___name__) (void)memcpy(dest.sa[index].___name__, source.sa[index].___name__.data(), source.sa[index].___name__.size())
__COPY_ITEM(index);
__COPY_ARR(sak);
__COPY_ARR(hashKey);
__COPY_ARR(salt);
__COPY_ITEM(ssci);
__COPY_ITEM(an);
__COPY_ITEM(nextPn);
__COPY_ITEM(enable);
}
};
macsecArgs->macsec.flags.en = this->flags.en;
macsecArgs->macsec.flags.nvm = this->flags.nvm;
copyConfig(this->rx, macsecArgs->macsec.rx);
copyConfig(this->tx, macsecArgs->macsec.tx);
macsecArgs->crc32 = crc32(0, (uint8_t*)&macsecArgs->macsec, sizeof(MACSEC_SETTINGS));
(void)report;
return true;
}
} // namespace icsneo

View File

@ -1,7 +1,7 @@
#include "icsneo/communication/message/neomessage.h" #include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/message/linmessage.h"
using namespace icsneo; using namespace icsneo;
@ -51,7 +51,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
eth.status.incompleteFrame = ethmsg->frameTooShort; eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits // TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled; //eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcsAvailable; //eth.status.xyz = ethmsg->fcs;
//eth.status.xyz = ethmsg->noPadding; //eth.status.xyz = ethmsg->noPadding;
break; break;
} }
@ -104,7 +104,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
} }
case Message::Type::CANErrorCount: { case Message::Type::CANErrorCount: {
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg; neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message); auto canerrormsg = std::static_pointer_cast<CANErrorMessage>(message);
canerror.transmitErrorCount = canerrormsg->transmitErrorCount; canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
canerror.receiveErrorCount = canerrormsg->receiveErrorCount; canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
canerror.status.canBusOff = canerrormsg->busOff; canerror.status.canBusOff = canerrormsg->busOff;

View File

@ -1,5 +1,5 @@
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
using namespace icsneo; using namespace icsneo;
@ -53,16 +53,18 @@ static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
return std::nullopt; return std::nullopt;
} }
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data(); const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
const HardwareCANErrorPacket* errPacket = (const HardwareCANErrorPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting if(errPacket->ERROR_INDICATOR) {
auto msg = std::make_shared<CANErrorMessage>();
const bool busOff = data->data[0] & 0b00100000; msg->receiveErrorCount = errPacket->REC;
msg->transmitErrorCount = errPacket->TEC;
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff); msg->errorWarn = HardwareCANErrorPacket::GetErrorWarn(errPacket->flags);
msg->errorPassive = HardwareCANErrorPacket::GetErrorPassive(errPacket->flags);
msg->busOff = HardwareCANErrorPacket::GetBusOff(errPacket->flags);
msg->errorCode = (CANErrorCode)errPacket->error_code;
msg->dataErrorCode = (CANErrorCode)errPacket->brs_data_error_code;
// This timestamp is raw off the device (in timestampResolution increments) // This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments // Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS; msg->timestamp = data->timestamp.TS;

View File

@ -16,8 +16,8 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
if(packet->Length < 4) if(packet->Length < 4)
return nullptr; return nullptr;
const size_t ethernetFrameSize = packet->Length - (sizeof(uint16_t) * 2); const size_t fcsSize = packet->header.FCS_AVAIL ? 4 : 0;
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize; const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + packet->Length;
const size_t bytestreamActualSize = bytestream.size(); const size_t bytestreamActualSize = bytestream.size();
if(bytestreamActualSize < bytestreamExpectedSize) if(bytestreamActualSize < bytestreamExpectedSize)
return nullptr; return nullptr;
@ -36,8 +36,6 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
message.preemptionEnabled = packet->header.PREEMPTION_ENABLED; message.preemptionEnabled = packet->header.PREEMPTION_ENABLED;
if(message.preemptionEnabled) if(message.preemptionEnabled)
message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4); message.preemptionFlags = (uint8_t)((rawWords[0] & 0x03F8) >> 4);
message.fcsAvailable = packet->header.FCS_AVAIL;
message.frameTooShort = packet->header.RUNT_FRAME; message.frameTooShort = packet->header.RUNT_FRAME;
if(message.frameTooShort) if(message.frameTooShort)
@ -47,11 +45,14 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
// Decoder will fix as it has information about the timestampResolution increments // Decoder will fix as it has information about the timestampResolution increments
message.timestamp = packet->timestamp.TS; message.timestamp = packet->timestamp.TS;
// Network ID is also not set, this will be fixed in the Decoder as well const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + sizeof(HardwareEthernetPacket);
const std::vector<uint8_t>::const_iterator dataend = databegin + packet->Length - fcsSize;
const std::vector<uint8_t>::const_iterator databegin = bytestream.begin() + (sizeof(HardwareEthernetPacket) - (sizeof(uint16_t) * 2));
const std::vector<uint8_t>::const_iterator dataend = databegin + ethernetFrameSize;
message.data.insert(message.data.begin(), databegin, dataend); message.data.insert(message.data.begin(), databegin, dataend);
if(fcsSize) {
uint32_t& fcs = message.fcs.emplace();
std::copy(dataend, dataend + fcsSize, (uint8_t*)&fcs);
}
return messagePtr; return messagePtr;
} }

View File

@ -88,6 +88,10 @@ 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 {
@ -218,8 +222,7 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
if(block) // Extensions say no if(block) // Extensions say no
return false; return false;
// Get component versions *after* the extension "onDeviceOpen" hooks (e.g. device reflashes) // Get component versions again *after* the extension "onDeviceOpen" hooks (e.g. device reflashes)
if(supportsComponentVersions()) { if(supportsComponentVersions()) {
if(auto compVersions = com->getComponentVersionsSync()) if(auto compVersions = com->getComponentVersionsSync())
componentVersions = std::move(*compVersions); componentVersions = std::move(*compVersions);
@ -246,6 +249,12 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
handleInternalMessage(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]() { heartbeatThread = std::thread([this]() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread(); EventManager::GetInstance().downgradeErrorsOnCurrentThread();
@ -271,12 +280,12 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
} }
while(!stopHeartbeatThread) { while(!stopHeartbeatThread) {
// Wait for 110ms for a possible heartbeat
std::this_thread::sleep_for(std::chrono::milliseconds(110));
std::unique_lock<std::mutex> recvLk(receivedMessageMutex); std::unique_lock<std::mutex> recvLk(receivedMessageMutex);
if(receivedMessage) { // Wait for 110ms for a possible heartbeat
if(heartbeatCV.wait_for(recvLk, std::chrono::milliseconds(110), [&]() { return receivedMessage; })) {
receivedMessage = false; receivedMessage = false;
} else { } 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 // 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 // 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 // packet format we expect here. As a result, status updates will not reach
@ -285,9 +294,8 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
// otherwise quiet stream. This lock makes sure suppressDisconnects() will // otherwise quiet stream. This lock makes sure suppressDisconnects() will
// block until we've either gotten our status update or disconnected from // block until we've either gotten our status update or disconnected from
// the device. // the device.
std::lock_guard<std::mutex> lk(heartbeatMutex); std::unique_lock<std::mutex> lk(heartbeatMutex);
if(heartbeatSuppressed()) if(heartbeatSuppressed()) continue;
continue;
// No heartbeat received, request a status // No heartbeat received, request a status
com->sendCommand(Command::RequestStatusUpdate); com->sendCommand(Command::RequestStatusUpdate);
@ -297,8 +305,8 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
receivedMessage = false; receivedMessage = false;
} else { } else {
if(!stopHeartbeatThread && !isDisconnected()) { if(!stopHeartbeatThread && !isDisconnected()) {
close();
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error); report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
com->driver->close();
} }
break; break;
} }
@ -348,6 +356,15 @@ APIEvent::Type Device::attemptToBeginCommunication() {
else else
versions = std::move(*maybeVersions); versions = std::move(*maybeVersions);
// Get component versions before the extension "onDeviceOpen" hooks so that we can properly check verisons
if(supportsComponentVersions()) {
if(auto compVersions = com->getComponentVersionsSync())
componentVersions = std::move(*compVersions);
else
return getCommunicationNotEstablishedError();
}
return APIEvent::Type::NoErrorFound; return APIEvent::Type::NoErrorFound;
} }
@ -371,10 +388,6 @@ bool Device::close() {
internalHandlerCallbackID = 0; internalHandlerCallbackID = 0;
if(heartbeatThread.joinable())
heartbeatThread.join();
stopHeartbeatThread = false;
forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onDeviceClose(); return true; }); forEachExtension([](const std::shared_ptr<DeviceExtension>& ext) { ext->onDeviceClose(); return true; });
return com->close(); return com->close();
} }
@ -806,12 +819,6 @@ std::shared_ptr<HardwareInfo> Device::getHardwareInfo(std::chrono::milliseconds
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullptr; return nullptr;
} }
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return nullptr;
}
auto filter = std::make_shared<MessageFilter>(Message::Type::HardwareInfo); auto filter = std::make_shared<MessageFilter>(Message::Type::HardwareInfo);
auto response = com->waitForMessageSync([this]() { auto response = com->waitForMessageSync([this]() {
@ -1691,7 +1698,10 @@ void Device::stopScriptStatusThreadIfNecessary(std::unique_lock<std::mutex> lk)
Lifetime Device::suppressDisconnects() { Lifetime Device::suppressDisconnects() {
std::lock_guard<std::mutex> lk(heartbeatMutex); std::lock_guard<std::mutex> lk(heartbeatMutex);
heartbeatSuppressedByUser++; heartbeatSuppressedByUser++;
return Lifetime([this] { std::lock_guard<std::mutex> lk2(heartbeatMutex); heartbeatSuppressedByUser--; }); return Lifetime([this] {
std::lock_guard<std::mutex> lk2(heartbeatMutex);
heartbeatSuppressedByUser--;
});
} }
void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) { void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) {
@ -1721,15 +1731,6 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
case Message::Type::RawMessage: { case Message::Type::RawMessage: {
auto rawMessage = std::static_pointer_cast<RawMessage>(message); auto rawMessage = std::static_pointer_cast<RawMessage>(message);
switch(rawMessage->network.getNetID()) { switch(rawMessage->network.getNetID()) {
case Network::NetID::Device: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg)
handleNeoVIMessage(std::move(canmsg));
break;
}
case Network::NetID::DeviceStatus: case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves // Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(rawMessage); handleDeviceStatus(rawMessage);
@ -1739,6 +1740,15 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
} }
break; break;
} }
case Message::Type::Frame: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg)
handleNeoVIMessage(std::move(canmsg));
break;
}
default: break; default: break;
} }
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
@ -1984,11 +1994,6 @@ std::optional<size_t> Device::getGenericBinarySize(uint16_t binaryIndex) {
return std::nullopt; return std::nullopt;
} }
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return std::nullopt;
}
std::vector<uint8_t> args = GenericBinaryStatusPacket::EncodeArguments(binaryIndex); std::vector<uint8_t> args = GenericBinaryStatusPacket::EncodeArguments(binaryIndex);
std::shared_ptr<Message> response = com->waitForMessageSync( std::shared_ptr<Message> response = com->waitForMessageSync(
@ -2051,6 +2056,40 @@ bool Device::readBinaryFile(std::ostream& stream, uint16_t binaryIndex) {
return true; return true;
} }
bool Device::writeBinaryFile(const std::vector<uint8_t>& in, uint16_t binaryIndex)
{
auto timeout = std::chrono::milliseconds(100);
auto size = in.size();
std::vector<uint8_t> arguments(sizeof(ExtendedDataMessage::ExtendedDataHeader) + ExtendedDataMessage::MaxExtendedDataBufferSize);
ExtendedDataMessage::ExtendedDataHeader& parameters = *reinterpret_cast<ExtendedDataMessage::ExtendedDataHeader*>(arguments.data());
auto filter = std::make_shared<MessageFilter>(Network::NetID::ExtendedData);
for (size_t offset = 0; offset < size; offset += ExtendedDataMessage::MaxExtendedDataBufferSize)
{
parameters.subCommand = ExtendedDataSubCommand::GenericBinaryWrite;
parameters.userValue = static_cast<uint32_t>(binaryIndex);
parameters.offset = static_cast<uint32_t>(offset);
parameters.length = static_cast<uint32_t>(std::min(ExtendedDataMessage::MaxExtendedDataBufferSize, size - offset));
(void)memcpy(&arguments[sizeof(ExtendedDataMessage::ExtendedDataHeader)], &in[offset], parameters.length);
std::shared_ptr<Message> response = com->waitForMessageSync(
[this, arguments]() {
return com->sendCommand(Command::ExtendedData, arguments);
},
filter,
timeout
);
if (!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return false;
}
}
return true;
}
bool Device::subscribeLiveData(std::shared_ptr<LiveDataCommandMessage> message) { bool Device::subscribeLiveData(std::shared_ptr<LiveDataCommandMessage> message) {
if(!supportsLiveData()) { if(!supportsLiveData()) {
report(APIEvent::Type::LiveDataNotSupported, APIEvent::Severity::Error); report(APIEvent::Type::LiveDataNotSupported, APIEvent::Severity::Error);
@ -3335,3 +3374,43 @@ std::optional<TC10StatusMessage> Device::getTC10Status(Network::NetID network) {
return *typed; return *typed;
} }
std::optional<GPTPStatus> Device::getGPTPStatus(std::chrono::milliseconds timeout) {
if(!supportsGPTP()) {
report(APIEvent::Type::GPTPNotSupported, APIEvent::Severity::Error);
return std::nullopt;
}
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return std::nullopt;
}
std::shared_ptr<Message> response = com->waitForMessageSync(
[this](){
return com->sendCommand(ExtendedCommand::GetGPTPStatus, {});
},
std::make_shared<MessageFilter>(Message::Type::GPTPStatus),
timeout
);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return std::nullopt;
}
auto retMsg = std::static_pointer_cast<GPTPStatus>(response);
if(!retMsg) {
return std::nullopt;
}
return *retMsg;
}
bool Device::writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex)
{
std::vector<uint8_t> raw;
message.EncodeFromMessage(raw, report);
return writeBinaryFile(raw, binaryIndex);
}

View File

@ -12,7 +12,7 @@ subprocess.call('cd ..; doxygen docs/icsneoc/Doxyfile', shell=True)
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'libicsneo' project = 'libicsneo'
copyright = '2024, Intrepid Control Systems, Inc.' copyright = '2024-2025, Intrepid Control Systems, Inc.'
author = 'Intrepid Control Systems, Inc.' author = 'Intrepid Control Systems, Inc.'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------

View File

@ -6,4 +6,5 @@ Python API
:members: :members:
:undoc-members: :undoc-members:
:show-inheritance: :show-inheritance:
:imported-members:
:special-members: __init__ :special-members: __init__

View File

@ -50,3 +50,41 @@ Receive CAN frames on HSCAN
# rx for 10s # rx for 10s
time.sleep(10) time.sleep(10)
Monitor Ethernet Status
=======================
.. code-block:: python
import icsneopy
import time
def main():
devices = icsneopy.find_all_devices()
if len(devices) == 0:
print("error: no devices found")
return False
device = devices[0]
print(f"info: monitoring Ethernet status on {device}")
def on_message(message):
print(f"info: network: {message.network}, state: {message.state}, speed: {message.speed}, duplex: {message.duplex}, mode: {message.mode}")
filter = icsneopy.MessageFilter(icsneopy.Message.Type.EthernetStatus)
callback = icsneopy.MessageCallback(on_message, filter)
device.add_message_callback(callback)
if not device.open():
print("error: unable to open device")
return False
if not device.go_online():
print("error: unable to go online")
return False
while True:
time.sleep(1)
main()

View File

@ -267,7 +267,7 @@ void printMessage(const std::shared_ptr<icsneo::Message>& message) {
} // end of icsneo::Message::Type::Frame } // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: { case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely // A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message); auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount
<< " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl; << " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl;
break; break;

View File

@ -252,7 +252,7 @@ int main() {
} // end of icsneo::Message::Type::Frame } // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: { case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely // A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message); auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);
// Print the error counts // Print the error counts
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount) std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount)

View File

@ -109,6 +109,7 @@ public:
LINSettingsNotAvailable = 0x2053, LINSettingsNotAvailable = 0x2053,
ModeNotFound = 0x2054, ModeNotFound = 0x2054,
AppErrorParsingFailed = 0x2055, AppErrorParsingFailed = 0x2055,
GPTPNotSupported = 0x2056,
// Transport Events // Transport Events
FailedToRead = 0x3000, FailedToRead = 0x3000,

View File

@ -51,6 +51,7 @@ enum class ExtendedCommand : uint16_t {
StartDHCPServer = 0x0016, StartDHCPServer = 0x0016,
StopDHCPServer = 0x0017, StopDHCPServer = 0x0017,
GetSupportedFeatures = 0x0018, GetSupportedFeatures = 0x0018,
GetGPTPStatus = 0x0019,
GetComponentVersions = 0x001A, GetComponentVersions = 0x001A,
Reboot = 0x001C, Reboot = 0x001C,
SetRootFSEntryFlags = 0x0027, SetRootFSEntryFlags = 0x0027,
@ -72,6 +73,7 @@ enum class ExtendedResponse : int32_t {
enum class ExtendedDataSubCommand : uint32_t { enum class ExtendedDataSubCommand : uint32_t {
GenericBinaryRead = 13, GenericBinaryRead = 13,
GenericBinaryWrite = 14,
}; };
#pragma pack(push,1) #pragma pack(push,1)

View File

@ -0,0 +1,27 @@
/*
* crc32.h
*
* Created on: Jun 22, 2020
* Author: BJones
*/
#pragma once
#ifndef CRC32_H_
#define CRC32_H_
#include <stdint.h>
/*
* When any data/buffer is run through calCRC(), then the resulting CRC value
* is appended to the end of the data/buffer and the data/buffer is rerun
* through calCRC(), the result will be CRC32_IDENT
*/
#define CRC32_IDENT (0x2144DF1C) /**< CRC check value */
#define CRC32_ISVALID(crc) ((crc) == CRC32_IDENT)
uint32_t crc32(uint32_t crc, const unsigned char* buf, uint32_t len);
uint32_t revcrc32(uint32_t crc, const unsigned char* buf, uint32_t len);
#endif // CRC32_H_

View File

@ -1,25 +0,0 @@
#ifndef __CANERRORCOUNTMESSAGE_H_
#define __CANERRORCOUNTMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
namespace icsneo {
class CANErrorCountMessage : public Message {
public:
CANErrorCountMessage(uint8_t tec, uint8_t rec, bool busOffFlag)
: Message(Message::Type::CANErrorCount), transmitErrorCount(tec), receiveErrorCount(rec), busOff(busOffFlag){}
Network network;
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
bool busOff;
};
}
#endif // __cplusplus
#endif

View File

@ -0,0 +1,40 @@
#ifndef __CANERRORMESSAGE_H_
#define __CANERRORMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
namespace icsneo {
enum class CANErrorCode : uint8_t
{
NoError = 0,
StuffError = 1,
FormError = 2,
AckError = 3,
Bit1Error = 4,
Bit0Error = 5,
CRCError = 6,
NoChange = 7
};
class CANErrorMessage : public Message {
public:
CANErrorMessage() : Message(Type::CANError) {}
Network network;
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
bool busOff;
bool errorPassive;
bool errorWarn;
CANErrorCode dataErrorCode;
CANErrorCode errorCode;
};
using CANErrorCountMessage = CANErrorMessage;
}
#endif // __cplusplus
#endif

View File

@ -35,7 +35,7 @@ class EthernetMessage : public Frame {
public: public:
bool preemptionEnabled = false; bool preemptionEnabled = false;
uint8_t preemptionFlags = 0; uint8_t preemptionFlags = 0;
bool fcsAvailable = false; std::optional<uint32_t> fcs;
bool frameTooShort = false; bool frameTooShort = false;
bool noPadding = false; bool noPadding = false;

View File

@ -0,0 +1,43 @@
#ifndef __ETHERNETSTATUSMESSAGE_H__
#define __ETHERNETSTATUSMESSAGE_H__
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include <memory>
namespace icsneo {
class EthernetStatusMessage : public Message {
public:
enum class LinkSpeed {
LinkSpeedAuto,
LinkSpeed10,
LinkSpeed100,
LinkSpeed1000,
LinkSpeed2500,
LinkSpeed5000,
LinkSpeed10000,
};
enum class LinkMode {
LinkModeAuto,
LinkModeMaster,
LinkModeSlave,
LinkModeInvalid,
};
EthernetStatusMessage(Network net, bool state, LinkSpeed speed, bool duplex, LinkMode mode) : Message(Type::EthernetStatus),
network(net), state(state), speed(speed), duplex(duplex), mode(mode) {}
Network network;
bool state;
LinkSpeed speed;
bool duplex;
LinkMode mode;
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
};
}; // namespace icsneo
#endif // __cplusplus
#endif // __ETHERNETSTATUSMESSAGE_H__

View File

@ -0,0 +1,103 @@
#ifndef __GPTPSTATUSMESSAGE_H_
#define __GPTPSTATUSMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/command.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
class GPTPStatus : public Message {
public:
typedef uint64_t TimeInterval;
typedef uint64_t ClockID;
struct Timestamp {
uint64_t seconds;
uint32_t nanoseconds;
double toSeconds() const {
static constexpr double billion = 1e9;
return (double)seconds + ((double)nanoseconds) / billion;
}
};
struct ScaledNanoSeconds {
int16_t nanosecondsMSB; // The most significant bits
int64_t nanosecondsLSB; // The least significant bits
int16_t fractionalNanoseconds; // Fractional part
};
struct PortID {
ClockID clockIdentity;
uint16_t portNumber;
};
struct ClockQuality {
uint8_t clockClass;
uint8_t clockAccuracy;
uint16_t offsetScaledLogVariance;
};
struct SystemID {
uint8_t priority1;
ClockQuality clockQuality;
uint8_t priority2;
ClockID clockID;
};
struct PriorityVector {
SystemID sysID;
uint16_t stepsRemoved;
PortID portID;
uint16_t portNumber;
};
struct ParentDS {
PortID parentPortIdentity;
int32_t cumulativeRateRatio;
ClockID grandmasterIdentity;
uint8_t gmClockQualityClockClass;
uint8_t gmClockQualityClockAccuracy;
uint16_t gmClockQualityOffsetScaledLogVariance;
uint8_t gmPriority1;
uint8_t gmPriority2;
};
struct CurrentDS {
uint16_t stepsRemoved;
TimeInterval offsetFromMaster;
ScaledNanoSeconds lastgmPhaseChange;
double lastgmFreqChange;
uint16_t gmTimeBaseIndicator;
uint32_t gmChangeCount;
uint32_t timeOfLastgmChangeEvent;
uint32_t timeOfLastgmPhaseChangeEvent;
uint32_t timeOfLastgmFreqChangeEvent;
};
GPTPStatus() : Message(Message::Type::GPTPStatus) {}
static std::shared_ptr<GPTPStatus> DecodeToMessage(std::vector<uint8_t>& bytes, const device_eventhandler_t& report);
Timestamp currentTime;
PriorityVector gmPriority;
int64_t msOffsetNs;
uint8_t isSync;
uint8_t linkStatus;
int64_t linkDelayNS;
uint8_t selectedRole;
uint8_t asCapable;
uint8_t isSyntonized;
Timestamp lastRXSyncTS; // t2 in IEEE 1588-2019 Figure-16
CurrentDS currentDS;
ParentDS parentDS;
bool shortFormat = false; // Set to true if the above variables weren't set (some firmware versions do not contain all the above variables)
};
}
#endif
#endif

View File

@ -0,0 +1,200 @@
#ifndef __MACSECMESSAGE_H__
#define __MACSECMESSAGE_H__
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/packet.h"
#include "icsneo/api/eventmanager.h"
#include <vector>
#include <memory>
#include <array>
#include <cstring>
namespace icsneo {
struct MACsecVLANTag
{
uint16_t vid; /*!< 12 bits */
uint8_t priCfi; /*!< PRI - 3 bits, CFI - 1bit */
};
struct MACsecMPLSOuter
{
uint32_t mplsLabel; /*!< 20 bits */
uint8_t exp; /*!< 3 bits */
};
enum class MACsecPacketType : uint8_t
{
NoVLANOrMPLS = 0,
SingleVLAN = 1,
DualVLAN = 2,
MPLS = 3,
SingleVLANFollowedByMPLS = 4,
DualVLANFollowedByMPLS = 5,
Unsupported = 6,
};
struct MACsecRule
{
uint8_t index;
std::array<uint8_t, 6> keyMacDa; /*!< MAC DA field extracted from the packet */
std::array<uint8_t, 6> maskMacDa; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
std::array<uint8_t, 6> keyMacSa; /*!< MAC SA field extracted from the packet */
std::array<uint8_t, 6> maskMacSa; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyEthertype; /*!< First E-Type found in the packet that doesn't match one of the preconfigured custom tag. */
uint16_t maskEthertype; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACsecVLANTag keyVlanTagOuter1; /*!< outermost/1st VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACsecMPLSOuter keyMplsOuter1;
MACsecVLANTag maskVlanTagOuter1; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACsecMPLSOuter maskMplsOuter1;
MACsecVLANTag keyVlanTagOuter2; /*!< 2nd outermost VLAN ID {8'd0, VLAN_ID[11:0]}, or 20-bit MPLS label. */
MACsecMPLSOuter keyMplsOuter2;
MACsecVLANTag maskVlanTagOuter2; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACsecMPLSOuter maskMplsOuter2;
uint16_t keyBonusData; /*!< 2 bytes of additional bonus data extracted from one of the custom tags. */
uint16_t maskBonusData; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyTagMatchBitmap; /*!< 8 bits total. Maps 1 to 1 bitwise with the set of custom tags. (set bit[N]=1 if check Nth custom tag) */
uint8_t maskTagMatchBitmap; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
MACsecPacketType keyPacketType; /*!< Encoded Packet Type, see MACSEC_PACKET_TYPE */
uint8_t maskPacketType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyInnerVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the second outermost VLAN Tag. */
uint16_t maskInnerVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint16_t keyOuterVlanType; /*!< 3 bits total. Encoded value indicating which VLAN TPID value matched for the outermost VLAN Tag. */
uint16_t maskOuterVlanType; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
uint8_t keyNumTags; /*!< 7 bits total. Number of VLAN/custom tags or MPLS lables detected. Ingress: before SecTag; Egress: total detected. Exclude MCS header tags. i.e. Bit 2: 2 tags/labels before SecTAG...Bit 6: 6 or more tags/labels before SecTAG. */
uint8_t maskNumTags; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
bool keyExpress; /*!< 1 bits. Express packet. */
uint8_t maskExpress; /*!< Set bits to 1 to mask/exclude corresponding flowid_tcam_data bit from compare */
bool isMpls;
bool enable;
};
struct MACsecMap
{
uint8_t index;
uint64_t secTagSci; /*!< Identifies the SecTAG SCI for this Flow. */
uint8_t secYIndex; /*!< index for entry in Egress secY Policy */
bool isControlPacket; /*!< Identifies all packets matching this index lookup as control packets. */
uint8_t scIndex; /*!< Identifies the SC for this Flow. */
uint8_t auxiliaryPlcy; /*!< Auxiliary policy bits. */
uint8_t ruleId; /*!< Identifies the Rule for this Flow. */
bool enable;
};
enum class MACsecValidateFrameType : uint8_t
{
Disabled = 0, /*!< Disable validation */
Check = 1, /*!< Enable validation, do not discard invalid frames*/
Strict = 2, /*!< Enable validation and discard invalid frames */
NA = 3 /*!< No processing or accounting */
};
enum class MACsecSecTagIcvStripType : uint8_t
{
StripBoth = 0, /*!< Strip both SecTag and ICV from packet */
StripSecTagPreserveICV = 1,
PreserveSecTagStripICV = 2, /*!< Preserve SecTag, Strip ICV */
PreserveBoth = 3 /*!< Preserve both SecTag and ICV */
};
enum class MACsecCipherSuiteType : uint8_t
{
GcmAes128 = 0,
GcmAes256 = 1,
GcmAes128Xpn = 2,
GcmAes256Xpn = 3
};
struct MACsecSecY
{
uint8_t index; /*!< Identifies the SecY for this Flow. */
bool controlledPortEnabled; /*!< Enable (or disable) operation of the Controlled port associated with this SecY */
MACsecValidateFrameType frameValidationType; /*!< see MACSEC_VALIDATEFRAME */
MACsecSecTagIcvStripType secTagIcvStripType; /*!< see MACSEC_STRIP_SECTAG_ICV */
MACsecCipherSuiteType cipher; /*!< Define the cipher suite to use for this SecY see MACSEC_CIPHER_SUITE */
uint8_t confidentialOffset; /*!< Define the number of bytes that are unencrypted following the SecTag. */
bool icvIncludesDaSa; /*!< When set, the outer DA/SA bytes are included in the authentication GHASH calculation */
bool replayProtect; /*!< Enables Anti-Replay protection */
uint32_t replayWindow; /*!< Unsigned value indicating the size of the anti-replay window. */
bool protectFrames; /*!< 0 = do not encrypt or authenticate this packet; 1 = always Authenticate frame and if SecTag.TCI.E = 1 encrypt the packet as well. */
uint8_t secTagOffset; /*!< Define the offset in bytes from either the start of the packet or a matching Etype depending on SecTag_Insertion_Mode. */
uint8_t secTagTci; /*!< Tag Control Information excluding the AN field which originates from the SA Policy table */
uint16_t mtu; /*!< Specifies the outgoing MTU for this SecY */
bool enable;
};
struct MACsecSc
{
uint8_t index; /*!< SC index. */
uint8_t secYIndex; /*!< SecY associated with this packet. */
uint64_t sci; /*!< The Secure Channel Identifier. */
uint8_t saIndex0; /*!< Define the 1st SA to use */
uint8_t saIndex1; /*!< Define the 2nd SA to use */
bool saIndex0InUse; /*!< Specifies whether 1st SA is in use or not. */
bool saIndex1InUse; /*!< Specifies whether 2nd SA is in use or not. */
bool enableAutoRekey; /*!< If enabled, then once the pn_threshold is reached, auto rekey will happen. */
bool isActiveSa1; /*!< If set, then sa_index1 is the currently active SA index. If cleared, the sa_index0 is the currently active SA index). */
bool enable;
};
struct MACsecSa
{
uint8_t index; /*!< SA index */
std::array<uint8_t, 32> sak; /*!< 256b SAK: Define the encryption key to be used to encrypte this packet. The lower 128 bits are used for 128-bit ciphers. */
std::array<uint8_t, 16> hashKey; /*!< 128b Hash Key: Key used for authentication. */
std::array<uint8_t, 12> salt; /*!< 96b Salt value: Salt value used in XPN ciphers. */
uint32_t ssci; /*!< 32b SSCI value: Short Secure Channel Identifier, used in XPN ciphers. */
uint8_t an; /*!< 2b SecTag Association Number (AN) */
uint64_t nextPn; /*!< 64b next_pn value: Next packet number to insert into outgoing packet on a particular SA. */
bool enable;
};
struct MACSecFlags
{
bool en; // '1' = enable; '0' = disable
};
/* MACSec Settings for 1 port/phy */
struct MACsecConfig
{
static constexpr int NumFlags = 1;
static constexpr int NumRules = 2;
static constexpr int NumMaps = 2;
static constexpr int NumSecY = 2;
static constexpr int NumSc = 2;
static constexpr int NumSa = 4;
MACSecFlags flags;
std::array<MACsecRule, NumRules> rule;
std::array<MACsecMap, NumMaps> map;
std::array<MACsecSecY, NumSecY> secy;
std::array<MACsecSc, NumSc> sc;
std::array<MACsecSa, NumSa> sa;
};
struct MACSecGlobalFlags
{
bool en; // '1' = enable; '0' = disable
bool nvm; // store macsec config in non-volatile memory
};
class MACsecMessage : public Message
{
public:
MACsecMessage(void) : Message(Message::Type::RawMessage) {}
MACSecGlobalFlags flags;
MACsecConfig rx;
MACsecConfig tx;
static std::shared_ptr<MACsecMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
bool EncodeFromMessage(std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) const;
};
}
#endif // __cplusplus
#endif

View File

@ -17,6 +17,7 @@ public:
Frame = 0, Frame = 0,
CANErrorCount = 0x100, CANErrorCount = 0x100,
CANError = 0x100,
LINHeaderOnly = 0x200, LINHeaderOnly = 0x200,
LINBreak = 0x201, LINBreak = 0x201,
@ -41,6 +42,8 @@ public:
HardwareInfo = 0x8010, HardwareInfo = 0x8010,
TC10Status = 0x8011, TC10Status = 0x8011,
AppError = 0x8012, AppError = 0x8012,
GPTPStatus = 0x8013,
EthernetStatus = 0x8014,
}; };
Message(Type t) : type(t) {} Message(Type t) : type(t) {}

View File

@ -13,6 +13,7 @@ namespace icsneo {
typedef uint16_t icscm_bitfield; typedef uint16_t icscm_bitfield;
#pragma pack(push,2)
struct HardwareCANPacket { struct HardwareCANPacket {
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream); static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report); static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
@ -50,6 +51,28 @@ struct HardwareCANPacket {
uint64_t IsExtended : 1; uint64_t IsExtended : 1;
} timestamp; } timestamp;
}; };
struct HardwareCANErrorPacket {
uint8_t error_code;
uint8_t brs_data_error_code;
uint16_t reserved;
uint16_t DLC : 4;
uint16_t : 4;
uint16_t ERROR_INDICATOR : 1;
uint16_t : 7;
uint8_t flags;
uint8_t REC;
uint8_t TEC;
static bool GetErrorWarn(uint8_t flags) { return flags & 0b0000'0001; }
static bool GetErrorPassive(uint8_t flags) { return flags & 0b0000'1000; }
static bool GetBusOff(uint8_t flags) { return flags & 0b0010'0000; }
};
#pragma pack(pop)
} }

View File

@ -10,6 +10,8 @@
namespace icsneo { namespace icsneo {
#pragma pack(push, 2)
typedef uint16_t icscm_bitfield; typedef uint16_t icscm_bitfield;
struct HardwareEthernetPacket { struct HardwareEthernetPacket {
@ -42,6 +44,8 @@ struct HardwareEthernetPacket {
uint16_t Length; uint16_t Length;
}; };
#pragma pack(pop)
} }
#endif // __cplusplus #endif // __cplusplus

View File

@ -40,6 +40,7 @@
#include "icsneo/communication/message/extendeddatamessage.h" #include "icsneo/communication/message/extendeddatamessage.h"
#include "icsneo/communication/message/livedatamessage.h" #include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/tc10statusmessage.h" #include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/macsecmessage.h"
#include "icsneo/communication/packet/genericbinarystatuspacket.h" #include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/packet/livedatapacket.h" #include "icsneo/communication/packet/livedatapacket.h"
#include "icsneo/device/extensions/flexray/controller.h" #include "icsneo/device/extensions/flexray/controller.h"
@ -50,6 +51,7 @@
#include "icsneo/disk/vsa/vsa.h" #include "icsneo/disk/vsa/vsa.h"
#include "icsneo/disk/vsa/vsaparser.h" #include "icsneo/disk/vsa/vsaparser.h"
#include "icsneo/communication/message/versionmessage.h" #include "icsneo/communication/message/versionmessage.h"
#include "icsneo/communication/message/gptpstatusmessage.h"
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \ #define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
@ -623,6 +625,7 @@ public:
std::optional<size_t> getGenericBinarySize(uint16_t binaryIndex); std::optional<size_t> getGenericBinarySize(uint16_t binaryIndex);
bool readBinaryFile(std::ostream& stream, uint16_t binaryIndex); bool readBinaryFile(std::ostream& stream, uint16_t binaryIndex);
bool writeBinaryFile(const std::vector<uint8_t>& in, uint16_t binaryIndex);
bool subscribeLiveData(std::shared_ptr<LiveDataCommandMessage> message); bool subscribeLiveData(std::shared_ptr<LiveDataCommandMessage> message);
bool unsubscribeLiveData(const LiveDataHandle& handle); bool unsubscribeLiveData(const LiveDataHandle& handle);
bool clearAllLiveData(); bool clearAllLiveData();
@ -727,12 +730,18 @@ public:
virtual bool supportsComponentVersions() const { return false; } virtual bool supportsComponentVersions() const { return false; }
virtual bool supportsTC10() const { return false; } virtual bool supportsTC10() const { return false; }
virtual bool supportsGPTP() const { return false; }
bool requestTC10Wake(Network::NetID network); bool requestTC10Wake(Network::NetID network);
bool requestTC10Sleep(Network::NetID network); bool requestTC10Sleep(Network::NetID network);
std::optional<TC10StatusMessage> getTC10Status(Network::NetID network); std::optional<TC10StatusMessage> getTC10Status(Network::NetID network);
std::optional<GPTPStatus> getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100));
/* MACsec support */
virtual bool writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex);
protected: protected:
bool online = false; bool online = false;

View File

@ -444,20 +444,21 @@ typedef struct LOGGER_SETTINGS_t
#define RAD_GPTP_NUM_PORTS 1 // 1 because only supported as gPTP endpoint #define RAD_GPTP_NUM_PORTS 1 // 1 because only supported as gPTP endpoint
typedef struct RAD_GPTP_SETTINGS_t typedef struct RAD_GPTP_SETTINGS_t
{ {
uint32_t neighborPropDelayThresh;//ns uint32_t neighborPropDelayThresh; //ns
uint32_t sys_phc_sync_interval;//ns uint32_t sys_phc_sync_interval; //ns
int8_t logPDelayReqInterval;// log2ms int8_t logPDelayReqInterval; // log2ms
int8_t logSyncInterval;// log2ms int8_t logSyncInterval; // log2ms
int8_t logAnnounceInterval;// log2ms int8_t logAnnounceInterval; // log2ms
uint8_t profile; uint8_t profile;
uint8_t priority1; uint8_t priority1;
uint8_t clockclass; uint8_t clockclass;
uint8_t clockaccuracy; uint8_t clockaccuracy;
uint8_t priority2; uint8_t priority2;
uint16_t offset_scaled_log_variance; uint16_t offset_scaled_log_variance;
uint8_t gPTPportRole[RAD_GPTP_NUM_PORTS]; uint8_t gptpPortRole;
uint8_t portEnable[RAD_GPTP_NUM_PORTS]; uint8_t gptpEnabledPort;
uint8_t rsvd[16]; uint8_t enableClockSyntonization;
uint8_t rsvd[15];
} RAD_GPTP_SETTINGS;//36 Bytes with RAD_GPTP_NUM_PORTS = 1 } RAD_GPTP_SETTINGS;//36 Bytes with RAD_GPTP_NUM_PORTS = 1
#define RAD_GPTP_SETTINGS_SIZE 36 #define RAD_GPTP_SETTINGS_SIZE 36

View File

@ -68,6 +68,10 @@ protected:
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override { std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0; return 0;
} }
bool supportsComponentVersions() const override { return true; }
bool supportsGPTP() const override { return true; }
}; };
} }

View File

@ -79,6 +79,8 @@ protected:
bool supportsLiveData() const override { return true; } bool supportsLiveData() const override { return true; }
bool supportsGPTP() const override { return true; }
std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override { std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override {
return 33*1024*1024; return 33*1024*1024;
} }
@ -90,6 +92,7 @@ protected:
bool supportsEraseMemory() const override { bool supportsEraseMemory() const override {
return true; return true;
} }
}; };
} }

View File

@ -36,6 +36,7 @@ public:
} }
bool supportsComponentVersions() const override { return true; } bool supportsComponentVersions() const override { return true; }
bool supportsGPTP() const override { return true; }
protected: protected:
NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {

View File

@ -40,6 +40,7 @@ public:
} }
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADA2B(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADA2B(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
@ -77,6 +78,7 @@ protected:
std::optional<MemoryAddress> getCoreminiStartAddressSD() const override { std::optional<MemoryAddress> getCoreminiStartAddressSD() const override {
return 0; return 0;
} }
}; };
} }

View File

@ -31,6 +31,7 @@ public:
} }
bool getEthPhyRegControlSupported() const override { return true; } bool getEthPhyRegControlSupported() const override { return true; }
bool supportsGPTP() const override { return true; }
protected: protected:
using Device::Device; using Device::Device;

View File

@ -45,6 +45,7 @@ public:
bool getEthPhyRegControlSupported() const override { return true; } bool getEthPhyRegControlSupported() const override { return true; }
bool supportsTC10() const override { return true; } bool supportsTC10() const override { return true; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADComet3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADComet3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {

View File

@ -61,6 +61,7 @@ public:
} }
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADGalaxy(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADGalaxy(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {

View File

@ -65,6 +65,7 @@ public:
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
bool supportsTC10() const override { return true; } bool supportsTC10() const override { return true; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADGalaxy2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADGalaxy2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {

View File

@ -22,10 +22,11 @@ public:
bool getEthPhyRegControlSupported() const override { return true; } bool getEthPhyRegControlSupported() const override { return true; }
bool supportsTC10() const override { return true; } bool supportsTC10() const override { return true; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADGigastar(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADGigastar(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADGigastarSettings>(makeDriver); initialize<RADGigastarSettings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
void setupPacketizer(Packetizer& packetizer) override { void setupPacketizer(Packetizer& packetizer) override {

View File

@ -76,7 +76,8 @@ namespace icsneo
bool getEthPhyRegControlSupported() const override { return true; } bool getEthPhyRegControlSupported() const override { return true; }
bool supportsTC10() const override { return true; } bool supportsTC10() const override { return true; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADGigastar2(neodevice_t neodevice, const driver_factory_t &makeDriver) : Device(neodevice) RADGigastar2(neodevice_t neodevice, const driver_factory_t &makeDriver) : Device(neodevice)
{ {

View File

@ -19,6 +19,7 @@ public:
ICSNEO_FINDABLE_DEVICE(RADMars, DeviceType::RADMars, "GL"); ICSNEO_FINDABLE_DEVICE(RADMars, DeviceType::RADMars, "GL");
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
bool supportsGPTP() const override { return true; }
protected: protected:
RADMars(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADMars(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {

View File

@ -14,7 +14,7 @@
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/flexray/flexraymessage.h" #include "icsneo/communication/message/flexray/flexraymessage.h"
#include "icsneo/communication/message/iso9141message.h" #include "icsneo/communication/message/iso9141message.h"
#include "icsneo/communication/message/canerrorcountmessage.h" #include "icsneo/communication/message/canerrormessage.h"
#include "icsneo/communication/message/ethphymessage.h" #include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/message/i2cmessage.h" #include "icsneo/communication/message/i2cmessage.h"
#include "icsneo/communication/message/a2bmessage.h" #include "icsneo/communication/message/a2bmessage.h"

View File

@ -0,0 +1,22 @@
#ifndef __WINDOWS_STRINGS_H__
#define __WINDOWS_STRINGS_H__
#ifdef __cplusplus
#include <string>
namespace icsneo {
// Helper function to convert UTF-16 to UTF-8 strings (wide to standard)
std::string convertWideString(const std::wstring& value);
// Helper function to convert UTF-8 to UTF-16 strings (standard to wide)
std::wstring convertStringToWide(const std::string& value);
};
#endif // __cplusplus
#endif // __WINDOWS_STRINGS_H__

View File

@ -95,6 +95,8 @@ bool FTD3XX::close() {
addEvent(ret, APIEvent::Severity::EventWarning); addEvent(ret, APIEvent::Severity::EventWarning);
} }
handle.reset();
setIsClosing(false); setIsClosing(false);
return true; return true;

View File

@ -88,6 +88,21 @@ void TCP::Socket::poll(uint16_t event, uint32_t msTimeout) {
} }
void TCP::Find(std::vector<FoundDevice>& found) { void TCP::Find(std::vector<FoundDevice>& found) {
static const auto tcpDisabled = []() -> bool {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const auto disabled = std::getenv("LIBICSNEO_DISABLE_TCP");
return disabled ? std::stoi(disabled) : false;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
};
if(tcpDisabled()) {
return;
}
static const auto MDNS_PORT = htons((unsigned short)5353); static const auto MDNS_PORT = htons((unsigned short)5353);
static const auto MDNS_IP = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U)); static const auto MDNS_IP = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));

View File

@ -34,9 +34,12 @@ PCAPDLL::PCAPDLL()
int len = GetSystemDirectory(dllPath, 480); // be safe int len = GetSystemDirectory(dllPath, 480); // be safe
if (len) { if (len) {
_tcscat_s(dllPath, 512, TEXT("\\Npcap")); _tcscat_s(dllPath, 512, TEXT("\\Npcap"));
cookie = AddDllDirectory(dllPath); WCHAR dllPath_w[512] = { 0 };
if (mbstowcs(dllPath_w, dllPath, 512)) {
cookie = AddDllDirectory(dllPath_w);
}
} }
dll = LoadLibraryEx(TEXT("wpcap.dll"), nullptr, LOAD_LIBRARY_SEARCH_USER_DIRS); dll = LoadLibraryEx(TEXT("wpcap.dll"), nullptr, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
if (cookie) if (cookie)
RemoveDllDirectory(cookie); RemoveDllDirectory(cookie);

View File

@ -2,6 +2,7 @@
#include <winsock2.h> #include <winsock2.h>
#include "icsneo/platform/windows/pcap.h" #include "icsneo/platform/windows/pcap.h"
#include "icsneo/platform/windows/strings.h"
#include "icsneo/communication/network.h" #include "icsneo/communication/network.h"
#include "icsneo/communication/communication.h" #include "icsneo/communication/communication.h"
#include "icsneo/communication/ethernetpacketizer.h" #include "icsneo/communication/ethernetpacketizer.h"
@ -11,14 +12,12 @@
#include <pcap.h> #include <pcap.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#pragma comment(lib, "IPHLPAPI.lib") #pragma comment(lib, "IPHLPAPI.lib")
#include <codecvt>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <locale> #include <locale>
using namespace icsneo; using namespace icsneo;
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::vector<PCAP::NetworkInterface> PCAP::knownInterfaces; std::vector<PCAP::NetworkInterface> PCAP::knownInterfaces;
@ -80,8 +79,8 @@ void PCAP::Find(std::vector<FoundDevice>& found) {
memcpy(iface.macAddress, aa->PhysicalAddress, sizeof(iface.macAddress)); memcpy(iface.macAddress, aa->PhysicalAddress, sizeof(iface.macAddress));
iface.nameFromWin32API = aa->AdapterName; iface.nameFromWin32API = aa->AdapterName;
iface.descriptionFromWin32API = converter.to_bytes(aa->Description); iface.descriptionFromWin32API = convertWideString(aa->Description);
iface.friendlyNameFromWin32API = converter.to_bytes(aa->FriendlyName); iface.friendlyNameFromWin32API = convertWideString(aa->FriendlyName);
if(iface.descriptionFromWin32API.find("LAN9512/LAN9514") != std::string::npos) { if(iface.descriptionFromWin32API.find("LAN9512/LAN9514") != std::string::npos) {
// This is an Ethernet EVB device // This is an Ethernet EVB device
iface.fullName = "Intrepid Ethernet EVB ( " + iface.friendlyNameFromWin32API + " : " + iface.descriptionFromWin32API + " )"; iface.fullName = "Intrepid Ethernet EVB ( " + iface.friendlyNameFromWin32API + " : " + iface.descriptionFromWin32API + " )";
@ -187,7 +186,7 @@ bool PCAP::IsHandleValid(neodevice_handle_t handle) {
return (netifIndex < knownInterfaces.size()); return (netifIndex < knownInterfaces.size());
} }
PCAP::PCAP(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice), pcap(PCAPDLL::getInstance()), ethPacketizer(err) { PCAP::PCAP(const device_eventhandler_t& eventHandler, neodevice_t& forDevice) : Driver(eventHandler), pcap(PCAPDLL::getInstance()), device(forDevice), ethPacketizer(eventHandler) {
if(IsHandleValid(device.handle)) { if(IsHandleValid(device.handle)) {
iface = knownInterfaces[(device.handle >> 24) & 0xFF]; iface = knownInterfaces[(device.handle >> 24) & 0xFF];
iface.fp = nullptr; // We're going to open our own connection to the interface. This should already be nullptr but just in case. iface.fp = nullptr; // We're going to open our own connection to the interface. This should already be nullptr but just in case.

View File

@ -1,4 +1,5 @@
#include "icsneo/platform/windows/registry.h" #include "icsneo/platform/windows/registry.h"
#include "icsneo/platform/windows/strings.h"
#include "icsneo/platform/windows.h" #include "icsneo/platform/windows.h"
#include <codecvt> #include <codecvt>
#include <vector> #include <vector>
@ -6,8 +7,6 @@
using namespace icsneo; using namespace icsneo;
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
class Key { class Key {
public: public:
Key(std::wstring path, bool readwrite = false); Key(std::wstring path, bool readwrite = false);
@ -95,8 +94,8 @@ bool Registry::Get(std::wstring path, std::wstring key, std::wstring& value) {
bool Registry::Get(std::string path, std::string key, std::string& value) { bool Registry::Get(std::string path, std::string key, std::string& value) {
std::wstring wvalue; std::wstring wvalue;
bool ret = Get(converter.from_bytes(path), converter.from_bytes(key), wvalue); bool ret = Get(convertStringToWide(path), convertStringToWide(key), wvalue);
value = converter.to_bytes(wvalue); value = convertWideString(wvalue);
return ret; return ret;
} }
@ -116,5 +115,5 @@ bool Registry::Get(std::wstring path, std::wstring key, uint32_t& value) {
} }
bool Registry::Get(std::string path, std::string key, uint32_t& value) { bool Registry::Get(std::string path, std::string key, uint32_t& value) {
return Get(converter.from_bytes(path), converter.from_bytes(key), value); return Get(convertStringToWide(path), convertStringToWide(key), value);
} }

View File

@ -0,0 +1,26 @@
#include <string>
#include <Windows.h>
#include <icsneo/platform/windows/strings.h>
// Helper function to convert UTF-16 to UTF-8 strings (wide to standard)
std::string icsneo::convertWideString(const std::wstring& value) {
// Get the width of the string (character count)
int width = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)value.c_str(), -1, 0, 0, NULL, NULL);
// Create the new string
std::string new_string(width+1, '\0');
// fill the new string with the converted characters
WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)value.c_str(), -1, new_string.data(), width, NULL, NULL);
return new_string;
};
// Helper function to convert UTF-8 to UTF-16 strings (standard to wide)
std::wstring icsneo::convertStringToWide(const std::string& value) {
// Get the width of the string (character count)
int width = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, NULL, 0);
// Create the new string
std::wstring new_string(width+1, '\0');
// fill the new string with the converted characters
MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, (LPWSTR)new_string.data(), width);
return new_string;
}

View File

@ -1,4 +1,5 @@
#include "icsneo/platform/windows/ftdi.h" #include "icsneo/platform/windows/ftdi.h"
#include "icsneo/platform/windows/strings.h"
#include "icsneo/platform/ftdi.h" #include "icsneo/platform/ftdi.h"
#include "icsneo/platform/registry.h" #include "icsneo/platform/registry.h"
#include "icsneo/device/founddevice.h" #include "icsneo/device/founddevice.h"
@ -15,7 +16,6 @@
using namespace icsneo; using namespace icsneo;
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
static const std::wstring DRIVER_SERVICES_REG_KEY = L"SYSTEM\\CurrentControlSet\\services\\"; static const std::wstring DRIVER_SERVICES_REG_KEY = L"SYSTEM\\CurrentControlSet\\services\\";
static const std::wstring ALL_ENUM_REG_KEY = L"SYSTEM\\CurrentControlSet\\Enum\\"; static const std::wstring ALL_ENUM_REG_KEY = L"SYSTEM\\CurrentControlSet\\Enum\\";
static constexpr unsigned int RETRY_TIMES = 5; static constexpr unsigned int RETRY_TIMES = 5;
@ -95,7 +95,7 @@ void VCP::Find(std::vector<FoundDevice>& found, std::vector<std::wstring> driver
if(!device.productId) if(!device.productId)
continue; continue;
std::string serial = converter.to_bytes(oss.str()); std::string serial = convertWideString(oss.str());
// The serial number should not have a path slash in it. If it does, that means we don't have the real serial. // The serial number should not have a path slash in it. If it does, that means we don't have the real serial.
if(serial.find_first_of('\\') != std::string::npos) { if(serial.find_first_of('\\') != std::string::npos) {
// The serial number was not in the first serenum key where we expected it. // The serial number was not in the first serenum key where we expected it.
@ -142,12 +142,12 @@ void VCP::Find(std::vector<FoundDevice>& found, std::vector<std::wstring> driver
// This is a device with characters in the serial number // This is a device with characters in the serial number
if(correctSerial.size() != 6) if(correctSerial.size() != 6)
continue; continue;
serial = converter.to_bytes(correctSerial); serial = convertWideString(correctSerial);
} }
else { else {
std::wstringstream soss; std::wstringstream soss;
soss << sn; soss << sn;
serial = converter.to_bytes(soss.str()); serial = convertWideString(soss.str());
} }
if(serial.find_first_of('\\') != std::string::npos) if(serial.find_first_of('\\') != std::string::npos)

View File

@ -1,5 +1,5 @@
[build-system] [build-system]
requires = ["scikit-build-core", "pybind11", "setuptools>=64", "setuptools-scm>=8"] requires = ["scikit-build-core", "pybind11", "setuptools>=64", "setuptools-scm>=8", "mypy"]
build-backend = "scikit_build_core.build" build-backend = "scikit_build_core.build"
[project] [project]
@ -47,3 +47,7 @@ local_scheme = "no-local-version"
[tool.scikit-build.cmake.define] [tool.scikit-build.cmake.define]
LIBICSNEO_ENABLE_BINDINGS_PYTHON = true LIBICSNEO_ENABLE_BINDINGS_PYTHON = true
LIBICSNEO_ENABLE_TCP = true LIBICSNEO_ENABLE_TCP = true
CMAKE_MSVC_RUNTIME_LIBRARY = "MultiThreaded"
[tool.cibuildwheel]
skip = "pp*"

View File

@ -0,0 +1,23 @@
#include <gtest/gtest.h>
#include <icsneo/platform/windows/strings.h>
#include <string>
TEST(WindowsUtilTest, testConvertWideString) {
#ifdef WIN32
std::wstring wideString(L"Hello World!");
auto normalString = icsneo::convertWideString(wideString);
ASSERT_STREQ(normalString.c_str(), "Hello World!");
#endif
}
TEST(WindowsUtilTest, testConvertStringToWide) {
#ifdef WIN32
std::string normalString("Hello World!");
auto wideString = icsneo::convertStringToWide(normalString);
ASSERT_STREQ(wideString.c_str(), L"Hello World!");
#endif
}

View File

@ -55,7 +55,7 @@
#include <io.h> #include <io.h>
#ifndef __MINGW32__ #ifndef __MINGW32__
#include "IP6_misc.h" #include "ip6_misc.h"
#endif #endif
#define caddr_t char* #define caddr_t char*