Device: Add network mutex support
parent
bf311ebe30
commit
c2f1022858
|
|
@ -1,5 +1,6 @@
|
|||
variables:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT}
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
|
@ -13,7 +14,7 @@ stages:
|
|||
build windows/x64:
|
||||
stage: build
|
||||
script:
|
||||
- CMD.EXE /C ci\build-windows64.bat
|
||||
- cmd /C ci\build-windows64.bat
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
|
|
@ -37,7 +38,7 @@ unit_test windows/x64:
|
|||
build windows/x86:
|
||||
stage: build
|
||||
script:
|
||||
- CMD.EXE /C ci\build-windows32.bat
|
||||
- cmd /C ci\build-windows32.bat
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
|
|
@ -67,7 +68,9 @@ unit_test windows/x86:
|
|||
script:
|
||||
- apt update -y
|
||||
- apt upgrade -y
|
||||
- apt install -y g++ ninja-build cmake libpcap-dev git
|
||||
- apt install -y g++ ninja-build cmake libpcap-dev git ca-certificates
|
||||
- echo "$ICS_IPA_CA_CRT" >/usr/local/share/ca-certificates/ica-ipa-ca.crt
|
||||
- update-ca-certificates --fresh
|
||||
- sh ci/build-posix.sh
|
||||
artifacts:
|
||||
when: always
|
||||
|
|
@ -93,7 +96,9 @@ unit_test windows/x86:
|
|||
script:
|
||||
- apt update -y
|
||||
- apt upgrade -y
|
||||
- apt install -y clang lld ninja-build cmake libpcap-dev git
|
||||
- apt install -y clang lld ninja-build cmake libpcap-dev git ca-certificates
|
||||
- echo "$ICS_IPA_CA_CRT" >/usr/local/share/ca-certificates/ica-ipa-ca.crt
|
||||
- update-ca-certificates --fresh
|
||||
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
|
||||
artifacts:
|
||||
when: always
|
||||
|
|
@ -175,7 +180,9 @@ unit_test linux/ubuntu/2404/amd64/clang:
|
|||
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
|
||||
- echo fastestmirror=True >>/etc/dnf/dnf.conf
|
||||
- dnf upgrade -y
|
||||
- dnf install -y g++ libpcap-devel cmake ninja-build git
|
||||
- dnf install -y g++ libpcap-devel cmake ninja-build git ca-certificates
|
||||
- echo "$ICS_IPA_CA_CRT" >/etc/pki/ca-trust/source/anchors/ica-ipa-ca.crt
|
||||
- update-ca-trust
|
||||
- sh ci/build-posix.sh
|
||||
artifacts:
|
||||
when: always
|
||||
|
|
@ -209,7 +216,9 @@ unit_test linux/ubuntu/2404/amd64/clang:
|
|||
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
|
||||
- echo fastestmirror=True >>/etc/dnf/dnf.conf
|
||||
- dnf upgrade -y
|
||||
- dnf install -y clang lld libpcap-devel cmake ninja-build git
|
||||
- dnf install -y clang lld libpcap-devel cmake ninja-build git ca-certificates
|
||||
- echo "$ICS_IPA_CA_CRT" >/etc/pki/ca-trust/source/anchors/ica-ipa-ca.crt
|
||||
- update-ca-trust
|
||||
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
|
||||
artifacts:
|
||||
when: always
|
||||
|
|
@ -289,22 +298,13 @@ unit_test linux/fedora/42/amd64/clang:
|
|||
build python/linux/amd64:
|
||||
stage: build
|
||||
tags:
|
||||
- linux-build
|
||||
image: python:3.13
|
||||
services:
|
||||
- name: docker:dind
|
||||
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
||||
command: ["dockerd-entrypoint.sh"]
|
||||
- linux-native-amd64
|
||||
variables:
|
||||
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh
|
||||
CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh
|
||||
CIBW_BUILD: "*manylinux*" # no musl
|
||||
CIBW_ARCHS: x86_64
|
||||
DOCKER_HOST: unix:///var/run/docker.sock
|
||||
DOCKER_DRIVER: overlay2
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install
|
||||
script:
|
||||
- curl -sSL https://get.docker.com/ | sh
|
||||
- sh ci/build-wheel-posix.sh
|
||||
artifacts:
|
||||
paths:
|
||||
|
|
@ -315,7 +315,7 @@ build python/linux/arm64:
|
|||
tags:
|
||||
- arm64-linux-build
|
||||
variables:
|
||||
CIBW_BEFORE_ALL: yum install -y flex && sh ci/bootstrap-libpcap.sh
|
||||
CIBW_BEFORE_ALL: sh ci/bootstrap-cibuildwheel.sh && sh ci/bootstrap-libpcap.sh
|
||||
CIBW_BUILD: "*manylinux*" # no musl
|
||||
CIBW_ARCHS: aarch64
|
||||
CIBW_ENVIRONMENT: CMAKE_PREFIX_PATH=/project/libpcap/install
|
||||
|
|
|
|||
|
|
@ -27,9 +27,8 @@ option(LIBICSNEO_ENABLE_DXX "Enable devices which communicate over D2XX/D3XX via
|
|||
|
||||
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
|
||||
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
|
@ -37,17 +36,13 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
|||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
set(LIBICSNEO_COMPILER_WARNINGS /W4)
|
||||
# http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html
|
||||
# Still supported until a suitable replacement is standardized
|
||||
add_definitions(-D_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
|
||||
add_definitions(-D_ITERATOR_DEBUG_LEVEL=0)
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
set(LIBICSNEO_COMPILER_WARNINGS -Wall -Wno-switch -Wno-unknown-pragmas)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
|
@ -201,6 +196,9 @@ set(SRC_FILES
|
|||
communication/message/gptpstatusmessage.cpp
|
||||
communication/message/ethernetstatusmessage.cpp
|
||||
communication/message/macsecmessage.cpp
|
||||
communication/message/networkmutexmessage.cpp
|
||||
communication/message/clientidmessage.cpp
|
||||
communication/message/transmitmessage.cpp
|
||||
communication/packet/flexraypacket.cpp
|
||||
communication/packet/canpacket.cpp
|
||||
communication/packet/a2bpacket.cpp
|
||||
|
|
@ -324,6 +322,7 @@ target_include_directories(icsneocpp
|
|||
target_link_libraries(icsneocpp PUBLIC Threads::Threads $<$<BOOL:${WIN32}>:ws2_32 iphlpapi>)
|
||||
set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||
target_compile_options(icsneocpp PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
|
||||
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
|
||||
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
|
||||
if(LIBICSNEO_ENABLE_FIRMIO)
|
||||
|
|
@ -383,6 +382,21 @@ if(LIBICSNEO_ENABLE_RAW_ETHERNET)
|
|||
endif(WIN32)
|
||||
endif(LIBICSNEO_ENABLE_RAW_ETHERNET)
|
||||
|
||||
# protobuf
|
||||
if(DEFINED ENV{LIBICSNEO_ICSPB_REPO})
|
||||
set(LIBICSNEO_ICSPB_REPO "$ENV{LIBICSNEO_ICSPB_REPO}")
|
||||
endif()
|
||||
if(NOT LIBICSNEO_ICSPB_REPO)
|
||||
set(LIBICSNEO_ICSPB_REPO https://github.com/intrepidcs/icspb.git)
|
||||
endif()
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(icspb
|
||||
GIT_REPOSITORY ${LIBICSNEO_ICSPB_REPO}
|
||||
GIT_TAG 2881dc4239319214dbf72fd3aa0427a4aefddd42
|
||||
)
|
||||
FetchContent_MakeAvailable(icspb)
|
||||
target_link_libraries(icsneocpp PRIVATE icspb::icspb)
|
||||
|
||||
if(LIBICSNEO_BUILD_ICSNEOC)
|
||||
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
|
||||
target_include_directories(icsneoc
|
||||
|
|
@ -394,6 +408,7 @@ if(LIBICSNEO_BUILD_ICSNEOC)
|
|||
)
|
||||
target_link_libraries(icsneoc PRIVATE icsneocpp)
|
||||
target_compile_features(icsneoc PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||
target_compile_options(icsneoc PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
|
||||
|
|
@ -408,6 +423,7 @@ if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
|
|||
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
|
||||
target_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||
target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC)
|
||||
target_compile_options(icsneoc-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
|
||||
|
|
@ -426,6 +442,7 @@ if(LIBICSNEO_BUILD_ICSNEOLEGACY)
|
|||
)
|
||||
target_link_libraries(icsneolegacy PRIVATE icsneocpp)
|
||||
target_compile_features(icsneolegacy PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||
target_compile_options(icsneolegacy PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC)
|
||||
|
|
@ -445,6 +462,7 @@ if(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC)
|
|||
target_link_libraries(icsneolegacy-static PUBLIC icsneocpp)
|
||||
target_compile_features(icsneolegacy-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||
target_compile_definitions(icsneolegacy-static PUBLIC ICSNEOC_BUILD_STATIC)
|
||||
target_compile_options(icsneolegacy-static PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
|
||||
endif()
|
||||
|
||||
add_subdirectory(bindings)
|
||||
|
|
@ -475,6 +493,8 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
|
|||
test/unit/periodictest.cpp
|
||||
)
|
||||
|
||||
target_compile_options(libicsneo-unit-tests PRIVATE ${LIBICSNEO_COMPILER_WARNINGS})
|
||||
|
||||
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
|
||||
target_link_libraries(libicsneo-unit-tests icsneocpp)
|
||||
|
||||
|
|
@ -487,4 +507,4 @@ endif()
|
|||
|
||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||
include(CPack)
|
||||
include(CPack)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
yum install -y flex ca-certificates || exit 1
|
||||
|
||||
echo "$ICS_IPA_CA_CRT" >/etc/pki/ca-trust/source/anchors/ica-ipa-ca.crt
|
||||
|
||||
update-ca-trust || exit 1
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/sh
|
||||
export CFLAGS="-Wall -Werror"
|
||||
export CXXFLAGS="-Wall -Werror"
|
||||
|
||||
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_EXAMPLES=ON \
|
||||
-DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=OFF || exit 1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
REM clean intermediate directories
|
||||
rmdir /s /q build
|
||||
mkdir build
|
||||
@setlocal
|
||||
@echo off
|
||||
|
||||
REM build
|
||||
cd build
|
||||
set CFLAGS=/WX /W4 /wd4127
|
||||
set CXXFLAGS=/WX /W4 /wd4127
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_UNIT_TESTS=ON -DLIBICSNEO_ENABLE_TCP=ON ..
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
cmake --build .
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
mkdir build >nul 2>&1
|
||||
|
||||
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Release -DLIBICSNEO_BUILD_UNIT_TESTS=ON ^
|
||||
-DLIBICSNEO_ENABLE_TCP=ON || exit /b 1
|
||||
|
||||
cmake --build build || exit /b 1
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@
|
|||
#include "icsneo/communication/message/readsettingsmessage.h"
|
||||
#include "icsneo/communication/message/versionmessage.h"
|
||||
#include "icsneo/communication/message/componentversionsmessage.h"
|
||||
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
|
||||
#include "icsneo/communication/message/clientidmessage.h"
|
||||
#include "icsneo/communication/icspb.h"
|
||||
|
||||
#include <commands/generic/v1/client_id.pb.h>
|
||||
#include <commands/network/v1/mutex.pb.h>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
|
|
@ -313,3 +319,32 @@ std::optional< std::vector<ComponentVersion> > Communication::getComponentVersio
|
|||
|
||||
return std::make_optional< std::vector<ComponentVersion> >(std::move(ver->versions));
|
||||
}
|
||||
|
||||
std::optional<uint32_t> Communication::getClientIDSync() {
|
||||
constexpr auto timeout = std::chrono::milliseconds(250);
|
||||
commands::generic::v1::ClientId msg;
|
||||
msg.Clear();
|
||||
|
||||
std::vector<uint8_t> payload = protoapi::getPayload(protoapi::Command::GET, msg);
|
||||
|
||||
std::shared_ptr<Message> response = waitForMessageSync(
|
||||
[this, payload](){
|
||||
return sendCommand(ExtendedCommand::ProtobufAPI, payload);
|
||||
},
|
||||
std::make_shared<MessageFilter>(Message::Type::ClientId),
|
||||
timeout
|
||||
);
|
||||
|
||||
if(!response) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto clientIdMessage = std::dynamic_pointer_cast<ClientIdMessage>(response);
|
||||
if(!clientIdMessage) {
|
||||
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return clientIdMessage->clientId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "icsneo/communication/message/gptpstatusmessage.h"
|
||||
#include "icsneo/communication/message/apperrormessage.h"
|
||||
#include "icsneo/communication/message/ethernetstatusmessage.h"
|
||||
#include "icsneo/communication/message/networkmutexmessage.h"
|
||||
#include "icsneo/communication/message/clientidmessage.h"
|
||||
#include "icsneo/communication/command.h"
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/communication/packet/canpacket.h"
|
||||
|
|
@ -44,6 +46,8 @@
|
|||
#include "icsneo/communication/packet/livedatapacket.h"
|
||||
#include "icsneo/communication/packet/hardwareinfopacket.h"
|
||||
#include "icsneo/communication/packet/spipacket.h"
|
||||
#include "icsneo/communication/icspb.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
@ -338,6 +342,25 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
|||
result = GPTPStatus::DecodeToMessage(packet->data, report);
|
||||
return true;
|
||||
}
|
||||
case ExtendedCommand::ProtobufAPI: {
|
||||
// get the proto id
|
||||
std::vector<uint8_t> responseBody(
|
||||
packet->data.begin() + sizeof(ExtendedResponseMessage::ResponseHeader),
|
||||
packet->data.end()
|
||||
);
|
||||
protoapi::Id protoId = protoapi::getProtoId(responseBody.data(), responseBody.size());
|
||||
switch(protoId) {
|
||||
case protoapi::Id::NetworkMutex:
|
||||
result = NetworkMutexMessage::DecodeToMessage(responseBody);
|
||||
return true;
|
||||
case protoapi::Id::ClientId:
|
||||
result = ClientIdMessage::DecodeToMessage(responseBody);
|
||||
return true;
|
||||
default:
|
||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case ExtendedCommand::GetDiskDetails:
|
||||
case ExtendedCommand::DiskFormatProgress: {
|
||||
std::vector<uint8_t> responseBody(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#include "icsneo/communication/message/clientidmessage.h"
|
||||
#include "icsneo/communication/icspb.h"
|
||||
#include "icsneo/communication/command.h"
|
||||
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
std::shared_ptr<ClientIdMessage> ClientIdMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||
ClientIdMessage decoded;
|
||||
commands::generic::v1::ClientId msg;
|
||||
|
||||
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(msg.has_client_id()) {
|
||||
decoded.clientId.emplace(msg.client_id());
|
||||
}
|
||||
|
||||
return std::make_shared<ClientIdMessage>(decoded);
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#include "icsneo/communication/message/networkmutexmessage.h"
|
||||
#include "icsneo/communication/icspb.h"
|
||||
#include "icsneo/communication/command.h"
|
||||
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
std::shared_ptr<NetworkMutexMessage> NetworkMutexMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||
NetworkMutexMessage decoded;
|
||||
commands::network::v1::NetworkMutex msg;
|
||||
|
||||
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(msg.has_client_id()) {
|
||||
decoded.owner_id.emplace(msg.client_id());
|
||||
}
|
||||
if(msg.has_type()) {
|
||||
decoded.type.emplace(static_cast<NetworkMutexType>(msg.type()));
|
||||
}
|
||||
if(msg.has_priority()) {
|
||||
decoded.priority.emplace(msg.priority());
|
||||
}
|
||||
if(msg.has_ttl()){
|
||||
decoded.ttlMs.emplace(msg.ttl());
|
||||
}
|
||||
if(msg.has_event()){
|
||||
decoded.event.emplace(static_cast<NetworkMutexEvent>(msg.event()));
|
||||
}
|
||||
for(int i = 0 ; i < msg.network_ids_size(); ++i){
|
||||
decoded.networks.emplace(static_cast<Network::NetID>(msg.network_ids(i)));
|
||||
}
|
||||
return std::make_shared<NetworkMutexMessage>(decoded);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForLock(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const std::set<Network::NetID>& networks, const device_eventhandler_t& /* report */) {
|
||||
commands::network::v1::NetworkMutex msg;
|
||||
for(auto&& network_id : networks) {
|
||||
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network_id));
|
||||
}
|
||||
msg.set_client_id(client_id);
|
||||
msg.set_priority(priority);
|
||||
msg.set_ttl(ttlMs);
|
||||
msg.set_type(static_cast<commands::network::v1::MutexType>(type));
|
||||
|
||||
return protoapi::getPayload(protoapi::Command::PUT, msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForLockAll(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const device_eventhandler_t& /* report */) {
|
||||
commands::network::v1::NetworkMutex msg;
|
||||
msg.set_client_id(client_id);
|
||||
msg.set_priority(priority);
|
||||
msg.set_ttl(ttlMs);
|
||||
msg.set_type(static_cast<commands::network::v1::MutexType>(type));
|
||||
msg.set_global(true);
|
||||
|
||||
return protoapi::getPayload(protoapi::Command::PUT, msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForUnlock(uint32_t client_id, const std::set<Network::NetID>& networks, const device_eventhandler_t& /* report */) {
|
||||
commands::network::v1::NetworkMutex msg;
|
||||
msg.Clear();
|
||||
for(auto&& network_id : networks)
|
||||
{
|
||||
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network_id));
|
||||
}
|
||||
msg.set_client_id(client_id);
|
||||
msg.set_release(true);
|
||||
|
||||
return protoapi::getPayload(protoapi::Command::PUT, msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForUnlockAll(uint32_t client_id, const device_eventhandler_t& /* report */) {
|
||||
commands::network::v1::NetworkMutex msg;
|
||||
msg.Clear();
|
||||
msg.set_client_id(client_id);
|
||||
msg.set_release(true);
|
||||
msg.set_global(true);
|
||||
|
||||
return protoapi::getPayload(protoapi::Command::PUT, msg);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> NetworkMutexMessage::EncodeArgumentsForStatus(Network::NetID network, const device_eventhandler_t& /* report */) {
|
||||
commands::network::v1::NetworkMutex msg;
|
||||
msg.add_network_ids(static_cast<commands::network::v1::NetworkId>(network));
|
||||
return protoapi::getPayload(protoapi::Command::GET, msg);
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
#include "icsneo/communication/message/transmitmessage.h"
|
||||
|
||||
// packet defs
|
||||
#include "icsneo/communication/packet/ethernetpacket.h"
|
||||
#include "icsneo/communication/packet/canpacket.h"
|
||||
#include "icsneo/communication/packet/linpacket.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
// copied.. TODO
|
||||
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd) {
|
||||
if(dataLength <= 8)
|
||||
return uint8_t(dataLength);
|
||||
|
||||
if(fd) {
|
||||
if(dataLength <= 12)
|
||||
return uint8_t(0x9);
|
||||
if(dataLength <= 16)
|
||||
return uint8_t(0xA);
|
||||
if(dataLength <= 20)
|
||||
return uint8_t(0xB);
|
||||
if(dataLength <= 24)
|
||||
return uint8_t(0xC);
|
||||
if(dataLength <= 32)
|
||||
return uint8_t(0xD);
|
||||
if(dataLength <= 48)
|
||||
return uint8_t(0xE);
|
||||
if(dataLength <= 64)
|
||||
return uint8_t(0xF);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> EncodeFromMessageEthernet(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
|
||||
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(frame);
|
||||
if(!ethmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return {};
|
||||
}
|
||||
std::vector<uint8_t> encoded;
|
||||
size_t messageLen = ethmsg->data.size();
|
||||
encoded.resize(sizeof(TransmitMessage) + messageLen);
|
||||
|
||||
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
|
||||
HardwareEthernetPacket* const ethpacket = (HardwareEthernetPacket*)(msg->commonHeader);
|
||||
uint8_t* const payload = encoded.data() + sizeof(TransmitMessage);
|
||||
|
||||
ethpacket->header.ENABLE_PADDING = ethmsg->noPadding ? 0 : 1;
|
||||
ethpacket->header.FCS_OVERRIDE = ethmsg->fcs ? 1 : 0;
|
||||
ethpacket->eid.txlen = static_cast<uint16_t>(messageLen);
|
||||
ethpacket->Length = static_cast<uint16_t>(messageLen);
|
||||
ethpacket->stats = ethmsg->description;
|
||||
ethpacket->NetworkID = static_cast<uint16_t>(ethmsg->network.getNetID());
|
||||
std::copy(ethmsg->data.begin(), ethmsg->data.end(), payload);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> EncodeFromMessageCAN(std::shared_ptr<Frame> frame, const device_eventhandler_t& report) {
|
||||
auto canmsg = std::dynamic_pointer_cast<CANMessage>(frame);
|
||||
if(!canmsg) {
|
||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||
return {};
|
||||
}
|
||||
if(canmsg->isCANFD && canmsg->isRemote) {
|
||||
report(APIEvent::Type::RTRNotSupported, APIEvent::Severity::Error);
|
||||
return {}; // RTR frames can not be used with CAN FD
|
||||
}
|
||||
std::vector<uint8_t> encoded;
|
||||
size_t messageLen = canmsg->data.size();
|
||||
size_t extraLen = 0;
|
||||
if(messageLen > 8) {
|
||||
extraLen = messageLen - 8;
|
||||
}
|
||||
encoded.resize(sizeof(TransmitMessage) + extraLen);
|
||||
|
||||
TransmitMessage* const msg = (TransmitMessage*)encoded.data();
|
||||
HardwareCANPacket* const canpacket = (HardwareCANPacket*)(msg->commonHeader);
|
||||
uint8_t* const extra_payload = encoded.data() + sizeof(TransmitMessage);
|
||||
|
||||
const size_t dataSize = canmsg->data.size();
|
||||
std::optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, canmsg->isCANFD);
|
||||
if(!dlc.has_value()) {
|
||||
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
||||
return {}; // Too much data for the protocol
|
||||
}
|
||||
// arb id
|
||||
if(canmsg->isExtended) {
|
||||
canpacket->header.IDE = 1;
|
||||
canpacket->header.SID = (canmsg->arbid >> 18) & 0x7FF;
|
||||
canpacket->eid.EID = (canmsg->arbid >> 6) & 0xfff;
|
||||
canpacket->dlc.EID2 = canmsg->arbid & 0x3f;
|
||||
} else {
|
||||
canpacket->header.IDE = 0;
|
||||
canpacket->header.SID = canmsg->arbid & 0x7FF;
|
||||
}
|
||||
|
||||
// DLC
|
||||
canpacket->dlc.DLC = dlc.value();
|
||||
|
||||
// FDF/BRS or remote frames
|
||||
if(canmsg->isCANFD) {
|
||||
canpacket->header.EDL = 1;
|
||||
canpacket->header.BRS = canmsg->baudrateSwitch ? 1 : 0;
|
||||
canpacket->header.ESI = canmsg->errorStateIndicator ? 1 : 0;
|
||||
canpacket->dlc.RTR = 0;
|
||||
|
||||
} else {
|
||||
canpacket->header.EDL = 0;
|
||||
canpacket->header.BRS = 0;
|
||||
canpacket->header.ESI = 0;
|
||||
canpacket->dlc.RTR = canmsg->isRemote ? 1 : 0;
|
||||
}
|
||||
// network
|
||||
canpacket->NetworkID = static_cast<uint16_t>(canmsg->network.getNetID());
|
||||
canpacket->Length = static_cast<uint16_t>(extraLen);
|
||||
// description id
|
||||
canpacket->stats = canmsg->description;
|
||||
// first 8 bytes
|
||||
std::copy(canmsg->data.begin(), canmsg->data.begin() + (messageLen > 8 ? 8 : messageLen), canpacket->data);
|
||||
// extra bytes
|
||||
if(extraLen > 0) {
|
||||
// copy extra data after the can packet
|
||||
std::copy(canmsg->data.begin() + 8, canmsg->data.end(), extra_payload);
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> /* frame */, const device_eventhandler_t& report) {
|
||||
// TODO
|
||||
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> TransmitMessage::EncodeFromMessage(std::shared_ptr<Frame> frame, uint32_t client_id, const device_eventhandler_t& report) {
|
||||
std::vector<uint8_t> result;
|
||||
switch(frame->network.getType()) {
|
||||
case Network::Type::Ethernet:
|
||||
result = EncodeFromMessageEthernet(frame, report);
|
||||
break;
|
||||
case Network::Type::CAN:
|
||||
result = EncodeFromMessageCAN(frame, report);
|
||||
break;
|
||||
case Network::Type::LIN:
|
||||
result = EncodeFromMessageLIN(frame, report);
|
||||
break;
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return result;
|
||||
}
|
||||
// common fields
|
||||
TransmitMessage* const msg = (TransmitMessage*)result.data();
|
||||
msg->options.clientId = client_id;
|
||||
msg->options.networkId = static_cast<uint32_t>(frame->network.getNetID());
|
||||
msg->options.reserved[0] = 0;
|
||||
msg->options.reserved[1] = 0;
|
||||
msg->options.reserved[2] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<ui
|
|||
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
|
||||
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
|
||||
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
|
||||
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
|
||||
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket);
|
||||
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "icsneo/device/extensions/deviceextension.h"
|
||||
#include "icsneo/disk/fat.h"
|
||||
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
|
||||
#include "icsneo/communication/message/networkmutexmessage.h"
|
||||
#include "icsneo/communication/message/transmitmessage.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // STL time functions
|
||||
|
|
@ -457,6 +459,29 @@ APIEvent::Type Device::attemptToBeginCommunication() {
|
|||
return getCommunicationNotEstablishedError();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
assignedClientId = com->getClientIDSync();
|
||||
networkMutexCallbackHandle = addMessageCallback(
|
||||
std::make_shared<MessageCallback>(
|
||||
[this](std::shared_ptr<Message> message) {
|
||||
auto netMutexMsg = std::static_pointer_cast<NetworkMutexMessage>(message);
|
||||
if(netMutexMsg->networks.size() && netMutexMsg->event.has_value()) {
|
||||
switch(*netMutexMsg->event) {
|
||||
case NetworkMutexEvent::Acquired:
|
||||
lockedNetworks.emplace(*netMutexMsg->networks.begin());
|
||||
break;
|
||||
case NetworkMutexEvent::Released: {
|
||||
auto it = lockedNetworks.find(*netMutexMsg->networks.begin());
|
||||
if (it != lockedNetworks.end())
|
||||
lockedNetworks.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
std::make_shared<MessageFilter>(Message::Type::NetworkMutex)
|
||||
)
|
||||
);
|
||||
|
||||
auto serial = com->getSerialNumberSync();
|
||||
int i = 0;
|
||||
while(!serial) {
|
||||
|
|
@ -895,9 +920,12 @@ bool Device::transmit(std::shared_ptr<Frame> frame) {
|
|||
return transmitStatusFromExtension;
|
||||
|
||||
std::vector<uint8_t> packet;
|
||||
if(assignedClientId.has_value()) {
|
||||
packet = TransmitMessage::EncodeFromMessage(frame, *assignedClientId, report);
|
||||
return packet.size() && com->sendCommand(ExtendedCommand::TransmitMessage, packet);
|
||||
}
|
||||
if(!com->encoder->encode(*com->packetizer, packet, frame))
|
||||
return false;
|
||||
|
||||
return com->sendPacket(packet);
|
||||
}
|
||||
|
||||
|
|
@ -3857,3 +3885,209 @@ std::shared_ptr<DiskDetails> Device::getDiskDetails(std::chrono::milliseconds ti
|
|||
return DiskDetails::Decode(extResponse->data, getDiskCount(), report);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<int> Device::lockNetworks(const std::set<Network::NetID>& networks, uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event)
|
||||
{
|
||||
if(!supportsNetworkMutex()) {
|
||||
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
if(!isOnline()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
if(!assignedClientId.has_value()) {
|
||||
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
constexpr auto timeout = std::chrono::milliseconds(250);
|
||||
|
||||
std::vector<uint8_t> payload = NetworkMutexMessage::EncodeArgumentsForLock(*assignedClientId, type, priority, ttlMs, networks, report);
|
||||
|
||||
std::optional<int> handle = std::nullopt;
|
||||
if(on_event) {
|
||||
handle.emplace(addMessageCallback(
|
||||
std::make_shared<MessageCallback>(
|
||||
on_event,
|
||||
std::make_shared<MessageFilter>(Message::Type::NetworkMutex)
|
||||
)
|
||||
));
|
||||
}
|
||||
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||
[this, payload](){
|
||||
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
|
||||
},
|
||||
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::ProtobufAPI),
|
||||
timeout
|
||||
);
|
||||
|
||||
if(!response) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto extResponse = std::dynamic_pointer_cast<ExtendedResponseMessage>(response);
|
||||
if(!extResponse) {
|
||||
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(extResponse->response != ExtendedResponse::OK && extResponse->response != ExtendedResponse::OperationPending) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool Device::unlockNetworks(const std::set<Network::NetID>& networks)
|
||||
{
|
||||
if(!supportsNetworkMutex()) {
|
||||
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
if(!assignedClientId.has_value()) {
|
||||
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
constexpr auto timeout = std::chrono::milliseconds(250);
|
||||
|
||||
std::vector<uint8_t> payload = NetworkMutexMessage::EncodeArgumentsForUnlock(*assignedClientId, networks, report);
|
||||
|
||||
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||
[this, payload](){
|
||||
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
|
||||
},
|
||||
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::ProtobufAPI),
|
||||
timeout
|
||||
);
|
||||
|
||||
if(!response) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto extResponse = std::dynamic_pointer_cast<ExtendedResponseMessage>(response);
|
||||
if(!extResponse) {
|
||||
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(extResponse->response != ExtendedResponse::OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkMutexMessage> Device::getNetworkMutexStatus(Network::NetID network)
|
||||
{
|
||||
if(!supportsNetworkMutex()) {
|
||||
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr auto timeout = std::chrono::milliseconds(1000);
|
||||
|
||||
std::vector<uint8_t> payload = NetworkMutexMessage::EncodeArgumentsForStatus(network, report);
|
||||
|
||||
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||
[this, payload](){
|
||||
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
|
||||
},
|
||||
std::make_shared<MessageFilter>(Message::Type::NetworkMutex),
|
||||
timeout
|
||||
);
|
||||
|
||||
return std::dynamic_pointer_cast<NetworkMutexMessage>(response);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<int> Device::lockAllNetworks(uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event)
|
||||
{
|
||||
if(!supportsNetworkMutex()) {
|
||||
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
if(!isOnline()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
if(!assignedClientId.has_value()) {
|
||||
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
constexpr auto timeout = std::chrono::milliseconds(1000);
|
||||
|
||||
std::vector<uint8_t> payload = NetworkMutexMessage::EncodeArgumentsForLockAll(*assignedClientId, type, priority, ttlMs, report);
|
||||
|
||||
int handle = addMessageCallback(
|
||||
std::make_shared<MessageCallback>(
|
||||
on_event,
|
||||
std::make_shared<MessageFilter>(Message::Type::NetworkMutex)
|
||||
)
|
||||
);
|
||||
|
||||
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||
[this, payload](){
|
||||
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
|
||||
},
|
||||
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::ProtobufAPI),
|
||||
timeout
|
||||
);
|
||||
|
||||
if(!response) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto extResponse = std::dynamic_pointer_cast<ExtendedResponseMessage>(response);
|
||||
if(!extResponse) {
|
||||
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(extResponse->response != ExtendedResponse::OK && extResponse->response != ExtendedResponse::OperationPending) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional(handle);
|
||||
}
|
||||
|
||||
bool Device::unlockAllNetworks()
|
||||
{
|
||||
if(!supportsNetworkMutex()) {
|
||||
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
if(!assignedClientId.has_value()) {
|
||||
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
constexpr auto timeout = std::chrono::milliseconds(1000);
|
||||
|
||||
std::vector<uint8_t> payload = NetworkMutexMessage::EncodeArgumentsForUnlockAll(*assignedClientId, report);
|
||||
|
||||
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||
[this, payload](){
|
||||
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
|
||||
},
|
||||
std::make_shared<ExtendedResponseFilter>(ExtendedCommand::ProtobufAPI),
|
||||
timeout
|
||||
);
|
||||
|
||||
if(!response) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto extResponse = std::dynamic_pointer_cast<ExtendedResponseMessage>(response);
|
||||
if(!extResponse) {
|
||||
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(extResponse->response != ExtendedResponse::OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ option(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE "Build the VSA example." ON)
|
|||
option(LIBICSNEO_BUILD_CPP_APP_ERROR_EXAMPLE "Build the app error example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_FLEXRAY_EXAMPLE "Build the FlexRay example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_SPI_EXAMPLE "Build the SPI example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_MUTEX_EXAMPLE "Build the NetworkMutex example." ON)
|
||||
|
||||
add_compile_options(${LIBICSNEO_COMPILER_WARNINGS})
|
||||
|
||||
if(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE)
|
||||
add_subdirectory(c/interactive)
|
||||
|
|
@ -67,4 +70,8 @@ endif()
|
|||
|
||||
if(LIBICSNEO_BUILD_CPP_SPI_EXAMPLE)
|
||||
add_subdirectory(cpp/spi)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_CPP_MUTEX_EXAMPLE)
|
||||
add_subdirectory(cpp/mutex)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
add_executable(libicsneocpp-mutex-example src/MutexExample.cpp)
|
||||
target_link_libraries(libicsneocpp-mutex-example icsneocpp)
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "icsneo/icsneocpp.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4996) // STL time functions
|
||||
#endif
|
||||
|
||||
static std::vector<std::shared_ptr<icsneo::Device>> findDevices(icsneo::DeviceType type)
|
||||
{
|
||||
std::vector<std::shared_ptr<icsneo::Device>> ret;
|
||||
for(auto&& dev : icsneo::FindAllDevices()) {
|
||||
if(dev->getType() == type) {
|
||||
ret.push_back(dev);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::vector<icsneo::Network> supported_nets;
|
||||
static std::unordered_map<icsneo::Network::NetID, icsneo::NetworkMutexEvent> network_mutex_states;
|
||||
constexpr uint32_t MUTEX_PRIORITY = 12345678;
|
||||
constexpr uint32_t MUTEX_TTL_MS = 2500;
|
||||
|
||||
static void on_mutex_event(std::shared_ptr<icsneo::Message> msg) {
|
||||
if(msg->type == icsneo::Message::Type::NetworkMutex) {
|
||||
auto nmm = std::static_pointer_cast<icsneo::NetworkMutexMessage>(msg);
|
||||
if(nmm->event.has_value() && nmm->networks.size())
|
||||
{
|
||||
auto network = *nmm->networks.begin();
|
||||
if(std::find_if(supported_nets.begin(), supported_nets.end(), [network](const icsneo::Network& net){ return net.getNetID() == network; }) != supported_nets.end())
|
||||
{
|
||||
std::cout << icsneo::Network::GetNetIDString(static_cast<icsneo::Network::NetID>(network)) << ": Mutex " << icsneo::NetworkMutexMessage::GetNetworkMutexEventString(nmm->event.value()) << std::endl;
|
||||
network_mutex_states[network] = *nmm->event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_mutexed_operation(std::shared_ptr<icsneo::Device> device, icsneo::Network::NetID network, std::function<void()>&& operation)
|
||||
{
|
||||
// Demonstrate taking a mutex on a single / group of networks
|
||||
auto lt = device->lockNetworks({network}, MUTEX_PRIORITY, MUTEX_TTL_MS, icsneo::NetworkMutexType::TxExclusive, on_mutex_event);
|
||||
if(lt.has_value()) {
|
||||
while(network_mutex_states.find(network) == network_mutex_states.end() ||
|
||||
network_mutex_states[network] != icsneo::NetworkMutexEvent::Acquired)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
operation();
|
||||
|
||||
device->unlockNetworks({network});
|
||||
while(network_mutex_states.find(network) != network_mutex_states.end() &&
|
||||
network_mutex_states[network] == icsneo::NetworkMutexEvent::Acquired)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
device->removeMessageCallback(*lt);
|
||||
} else {
|
||||
std::cout << "Failed to acquire mutex for " << icsneo::Network::GetNetIDString(network) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Print version
|
||||
std::cout << "libicsneo version " << icsneo::GetVersion() << std::endl;
|
||||
|
||||
std::cout << "\nFinding devices... " << std::flush;
|
||||
auto devices = findDevices(icsneo::DeviceType::FIRE3);
|
||||
// You now hold the shared_ptrs for these devices, you are considered to "own" these devices from a memory perspective
|
||||
std::cout << "OK, " << devices.size() << " device" << (devices.size() == 1 ? "" : "s") << " found" << std::endl;
|
||||
|
||||
// List off the devices
|
||||
for(auto& device : devices)
|
||||
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
for(auto& device : devices) {
|
||||
std::cout << "Connecting to " << device->describe() << "... ";
|
||||
bool ret = device->open();
|
||||
if(!ret) { // Failed to open
|
||||
std::cout << "FAIL" << std::endl;
|
||||
std::cout << icsneo::GetLastError() << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
std::cout << "OK" << std::endl;
|
||||
|
||||
supported_nets = device->getSupportedTXNetworks();
|
||||
|
||||
device->goOnline();
|
||||
|
||||
// Demonstrate lock and unlock all networks
|
||||
std::cout << "Requesting global exclusive network mutex" << std::endl;
|
||||
auto lt = device->lockAllNetworks(MUTEX_PRIORITY, MUTEX_TTL_MS, icsneo::NetworkMutexType::TxExclusive, on_mutex_event);
|
||||
if(lt.has_value()) {
|
||||
// wait until we have the mutex on all networks
|
||||
auto all_nets = device->getSupportedTXNetworks();
|
||||
for(auto net = all_nets.begin(); net != all_nets.end();) {
|
||||
auto state = network_mutex_states.find(net->getNetID());
|
||||
if(state != network_mutex_states.end() && state->second == icsneo::NetworkMutexEvent::Acquired) {
|
||||
net = all_nets.erase(net);
|
||||
} else {
|
||||
++net;
|
||||
}
|
||||
}
|
||||
std::cout << "Acquired mutex for all supported networks on " << device->describe() << std::endl;
|
||||
|
||||
// request release
|
||||
if(device->unlockAllNetworks()) {
|
||||
std::cout << "Requested release of all networks" << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed to request release of all networks" << std::endl;
|
||||
}
|
||||
|
||||
// wait until we have released the mutex on all networks
|
||||
all_nets = device->getSupportedTXNetworks();
|
||||
for(auto net = all_nets.begin(); net != all_nets.end();) {
|
||||
auto state = network_mutex_states.find(net->getNetID());
|
||||
if(state == network_mutex_states.end() || state->second == icsneo::NetworkMutexEvent::Released) {
|
||||
net = all_nets.erase(net);
|
||||
} else {
|
||||
++net;
|
||||
}
|
||||
}
|
||||
std::cout << "released mutex on all supported networks" << std::endl;
|
||||
|
||||
device->removeMessageCallback(*lt);
|
||||
} else {
|
||||
std::cout << "Failed to acquire global mutex" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Doing mutexed operation on DWCAN 01" << std::endl;
|
||||
do_mutexed_operation(device, icsneo::Network::NetID::DWCAN_01, [&](){
|
||||
auto tx_message = std::make_shared<icsneo::CANMessage>();
|
||||
tx_message->arbid = 0x12;
|
||||
tx_message->isCANFD = true;
|
||||
tx_message->baudrateSwitch = true;
|
||||
tx_message->data.resize(64);
|
||||
tx_message->network = icsneo::Network::NetID::DWCAN_01;
|
||||
constexpr auto txInterval = std::chrono::microseconds(500);
|
||||
auto nextRefresh = std::chrono::steady_clock::now() + std::chrono::milliseconds(MUTEX_TTL_MS / 2);
|
||||
auto nextTx = std::chrono::steady_clock::now() + txInterval;
|
||||
size_t numTx = 0;
|
||||
while(numTx < 5000) {
|
||||
if(std::chrono::steady_clock::now() < nextTx) {
|
||||
continue;
|
||||
}
|
||||
nextTx = std::chrono::steady_clock::now() + txInterval;
|
||||
std::iota(tx_message->data.begin(), tx_message->data.end(), (uint8_t)(numTx & 0xFF));
|
||||
if(device->transmit(tx_message)) {
|
||||
++numTx;
|
||||
}
|
||||
// check the mutex periodically - every 200 messages for demonstrative purposes
|
||||
if(std::chrono::steady_clock::now() > nextRefresh) {
|
||||
auto status = device->getNetworkMutexStatus(icsneo::Network::NetID::DWCAN_01);
|
||||
if(!status) {
|
||||
std::cout << "failed to poll status of network mutex for DWCAN 01" << std::endl;
|
||||
} else {
|
||||
std::cout << "DWCAN 01 mutex TTL: " << *status->ttlMs << " ms" << std::endl;
|
||||
}
|
||||
std::cout << "refreshing mutex on DWCAN 01, current tx count: " << numTx << std::endl;
|
||||
(void)device->lockNetworks({icsneo::Network::NetID::DWCAN_01}, MUTEX_PRIORITY, MUTEX_TTL_MS, icsneo::NetworkMutexType::TxExclusive, nullptr);
|
||||
nextRefresh = std::chrono::steady_clock::now() + std::chrono::milliseconds(MUTEX_TTL_MS / 2);
|
||||
}
|
||||
}
|
||||
});
|
||||
std::cout << "Completed mutexed operation on DWCAN 01" << std::endl;
|
||||
|
||||
|
||||
std::cout << "Doing mutexed operation on Ethernet 03" << std::endl;
|
||||
do_mutexed_operation(device, icsneo::Network::NetID::ETHERNET_03, [&](){
|
||||
auto tx_message = std::make_shared<icsneo::EthernetMessage>();
|
||||
tx_message->data.resize(512);
|
||||
// set mac addresses and ethertype
|
||||
std::iota(tx_message->data.begin(), tx_message->data.begin() + 14, static_cast<uint8_t>(0x01));
|
||||
tx_message->network = icsneo::Network::NetID::ETHERNET_03;
|
||||
constexpr auto txInterval = std::chrono::microseconds(250);
|
||||
auto nextRefresh = std::chrono::steady_clock::now() + std::chrono::milliseconds(MUTEX_TTL_MS / 2);
|
||||
auto nextTx = std::chrono::steady_clock::now() + txInterval;
|
||||
size_t numTx = 0;
|
||||
while(numTx < 50000) {
|
||||
if(std::chrono::steady_clock::now() < nextTx) {
|
||||
continue;
|
||||
}
|
||||
nextTx = std::chrono::steady_clock::now() + txInterval;
|
||||
// keep the mac addresses and ethertype constant
|
||||
std::iota(tx_message->data.begin() + 14, tx_message->data.end(), (uint8_t)(numTx & 0xFF));
|
||||
if(device->transmit(tx_message)) {
|
||||
++numTx;
|
||||
}
|
||||
if(std::chrono::steady_clock::now() > nextRefresh) {
|
||||
auto status = device->getNetworkMutexStatus(icsneo::Network::NetID::ETHERNET_03);
|
||||
if(!status) {
|
||||
std::cout << "failed to poll status of network mutex for Ethernet 03" << std::endl;
|
||||
} else {
|
||||
std::cout << "Ethernet 03 mutex TTL: " << *status->ttlMs << " ms" << std::endl;
|
||||
}
|
||||
std::cout << "refreshing mutex on Ethernet 03, current tx count: " << numTx << std::endl;
|
||||
(void)device->lockNetworks({icsneo::Network::NetID::ETHERNET_03}, MUTEX_PRIORITY, MUTEX_TTL_MS, icsneo::NetworkMutexType::TxExclusive, nullptr);
|
||||
nextRefresh = std::chrono::steady_clock::now() + std::chrono::milliseconds(MUTEX_TTL_MS / 2);
|
||||
}
|
||||
}
|
||||
});
|
||||
std::cout << "Completed mutexed operation on Ethernet 03" << std::endl;
|
||||
|
||||
device->close();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -62,6 +62,8 @@ enum class ExtendedCommand : uint16_t {
|
|||
RequestTC10Wake = 0x003D,
|
||||
RequestTC10Sleep = 0x003E,
|
||||
GetTC10Status = 0x003F,
|
||||
ProtobufAPI = 0x0041,
|
||||
TransmitMessage = 0x0042,
|
||||
};
|
||||
|
||||
enum class ExtendedResponse : int32_t {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ public:
|
|||
std::optional< std::vector< std::optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||
std::shared_ptr<LogicalDiskInfoMessage> getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||
std::optional< std::vector<ComponentVersion> > getComponentVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||
std::optional<uint32_t> getClientIDSync();
|
||||
|
||||
|
||||
int addMessageCallback(const std::shared_ptr<MessageCallback>& cb);
|
||||
bool removeMessageCallback(int id);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef COMMUNICATION_PROTO_API_IMPL_H
|
||||
#define COMMUNICATION_PROTO_API_IMPL_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#include <common/v1/proto_header.pb.h>
|
||||
#include <commands/generic/v1/client_id.pb.h>
|
||||
#include <commands/network/v1/mutex.pb.h>
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
namespace icsneo {
|
||||
namespace protoapi {
|
||||
|
||||
enum class Command : uint8_t {
|
||||
Unspecified = 0,
|
||||
GET = 1,
|
||||
PUT = 2,
|
||||
PATCH = 3,
|
||||
};
|
||||
|
||||
enum class Id : uint32_t {
|
||||
Unspecified = 0,
|
||||
MfgConfig = 1,
|
||||
CpuId = 2,
|
||||
NetworkMutex = 3,
|
||||
ClientId = 4,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct IDLookup {
|
||||
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_UNSPECIFIED;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IDLookup<commands::network::v1::NetworkMutex> {
|
||||
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_NETWORK_MUTEX;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IDLookup<commands::generic::v1::ClientId> {
|
||||
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_GET_CLIENT_ID;
|
||||
};
|
||||
|
||||
inline uint8_t* writeVarint32(uint32_t value, uint8_t* target) {
|
||||
return google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(value, target);
|
||||
}
|
||||
|
||||
inline const uint8_t* readVarint32(uint32_t& value, const uint8_t* source) {
|
||||
value = 0;
|
||||
do {
|
||||
value <<= 7;
|
||||
value += *source & 0x7F;
|
||||
} while(*source++ & 0x80);
|
||||
return source;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<uint8_t> getPayload(Command command, const T& msg) {
|
||||
std::vector<uint8_t> payload;
|
||||
constexpr uint32_t proto_version = 1;
|
||||
common::v1::ProtoHeader hdr;
|
||||
hdr.set_version(proto_version);
|
||||
hdr.set_api_command(static_cast<common::v1::ApiCommand>(command));
|
||||
hdr.set_auth_method(common::v1::AuthMethod::PROTO_API_AUTH_NONE); // TODO
|
||||
hdr.set_proto_id(IDLookup<T>::value);
|
||||
|
||||
static constexpr size_t varint_size_max = 5;
|
||||
size_t header_size = hdr.ByteSizeLong();
|
||||
size_t msg_size = msg.ByteSizeLong();
|
||||
size_t payload_size_max = header_size + msg_size + (varint_size_max * 2); // TODO: auth
|
||||
payload.resize(payload_size_max);
|
||||
|
||||
uint8_t* target = payload.data();
|
||||
|
||||
target = writeVarint32(static_cast<uint32_t>(header_size), target);
|
||||
hdr.SerializeToArray(target, static_cast<int>(header_size));
|
||||
target += header_size;
|
||||
if(msg_size) {
|
||||
target = writeVarint32(static_cast<uint32_t>(msg_size), target);
|
||||
msg.SerializeToArray(target, static_cast<int>(msg_size));
|
||||
target += msg_size;
|
||||
}
|
||||
payload.resize(target - payload.data());
|
||||
return payload;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool processResponse(const uint8_t* payload, size_t /* payload_length */, T& msg) {
|
||||
// TODO: we should probably check payload_length throughout to not go past the end of the supplied buffer
|
||||
|
||||
// header
|
||||
common::v1::ProtoHeader hdr;
|
||||
uint32_t length;
|
||||
const uint8_t* serialized = readVarint32(length, payload);
|
||||
if(!hdr.ParseFromArray(serialized, length)) {
|
||||
return false;
|
||||
}
|
||||
// message payload
|
||||
serialized = readVarint32(length, serialized + length);
|
||||
if(!msg.ParseFromArray(serialized, length)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Id getProtoId(const uint8_t* payload, size_t /* payload_length */) {
|
||||
// TODO: we should probably check this throughout to not go past the end of the supplied buffer
|
||||
|
||||
// header
|
||||
common::v1::ProtoHeader hdr;
|
||||
uint32_t length;
|
||||
const uint8_t* serialized = readVarint32(length, payload);
|
||||
if(!hdr.ParseFromArray(serialized, length)) {
|
||||
return Id::Unspecified;
|
||||
}
|
||||
return static_cast<Id>(hdr.proto_id());
|
||||
}
|
||||
|
||||
} // namespace protoapi
|
||||
} // namespace icsneo
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef CLIENT_ID_MESSAGE_H_
|
||||
#define CLIENT_ID_MESSAGE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include "icsneo/communication/network.h"
|
||||
#include "icsneo/communication/message/message.h"
|
||||
#include "icsneo/api/eventmanager.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class ClientIdMessage : public Message {
|
||||
public:
|
||||
ClientIdMessage() : Message(Message::Type::ClientId) {}
|
||||
static std::shared_ptr<ClientIdMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||
|
||||
std::optional<uint32_t> clientId;
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif
|
||||
|
|
@ -45,6 +45,8 @@ public:
|
|||
GPTPStatus = 0x8013,
|
||||
EthernetStatus = 0x8014,
|
||||
LogData = 0x8015,
|
||||
NetworkMutex = 0x8016,
|
||||
ClientId = 0x8017,
|
||||
};
|
||||
|
||||
Message(Type t) : type(t) {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef __NETWORKMUTEXMESSAGE_H_
|
||||
#define __NETWORKMUTEXMESSAGE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include "icsneo/communication/network.h"
|
||||
#include "icsneo/communication/message/message.h"
|
||||
#include "icsneo/communication/message/extendedresponsemessage.h"
|
||||
#include "icsneo/api/eventmanager.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
enum class NetworkMutexType : uint8_t {
|
||||
Shared = 0,
|
||||
TxExclusive = 1,
|
||||
ExternalExclusive = 2,
|
||||
FullyExclusive = 3,
|
||||
};
|
||||
|
||||
enum class NetworkMutexEvent : uint8_t {
|
||||
Released = 0,
|
||||
Expired = 1,
|
||||
Preempted = 2,
|
||||
Queued = 3,
|
||||
Acquired = 4,
|
||||
};
|
||||
|
||||
class NetworkMutexMessage : public Message
|
||||
{
|
||||
public:
|
||||
NetworkMutexMessage() : Message(Message::Type::NetworkMutex) {}
|
||||
|
||||
static std::shared_ptr<NetworkMutexMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||
static std::vector<uint8_t> EncodeArgumentsForLock(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const std::set<Network::NetID>& networks, const device_eventhandler_t& report);
|
||||
static std::vector<uint8_t> EncodeArgumentsForLockAll(uint32_t client_id, NetworkMutexType type, uint32_t priority, uint32_t ttlMs, const device_eventhandler_t& report);
|
||||
static std::vector<uint8_t> EncodeArgumentsForUnlock(uint32_t client_id, const std::set<Network::NetID>& networks, const device_eventhandler_t& report);
|
||||
static std::vector<uint8_t> EncodeArgumentsForUnlockAll(uint32_t client_id, const device_eventhandler_t& report);
|
||||
static std::vector<uint8_t> EncodeArgumentsForStatus(Network::NetID network, const device_eventhandler_t& report);
|
||||
|
||||
static const char* GetNetworkMutexTypeString(NetworkMutexType type) {
|
||||
switch(type) {
|
||||
case icsneo::NetworkMutexType::Shared:
|
||||
return "Shared";
|
||||
case icsneo::NetworkMutexType::TxExclusive:
|
||||
return "TxExclusive";
|
||||
case icsneo::NetworkMutexType::ExternalExclusive:
|
||||
return "ExternalExclusive";
|
||||
case icsneo::NetworkMutexType::FullyExclusive:
|
||||
return "FullyExclusive";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* GetNetworkMutexEventString(NetworkMutexEvent event) {
|
||||
switch(event) {
|
||||
case icsneo::NetworkMutexEvent::Acquired:
|
||||
return "Acquired";
|
||||
case icsneo::NetworkMutexEvent::Released:
|
||||
return "Released";
|
||||
case icsneo::NetworkMutexEvent::Preempted:
|
||||
return "Preempted";
|
||||
case icsneo::NetworkMutexEvent::Expired:
|
||||
return "Expired";
|
||||
case icsneo::NetworkMutexEvent::Queued:
|
||||
return "Queued";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint32_t> owner_id;
|
||||
std::optional<NetworkMutexType> type;
|
||||
std::optional<uint32_t> priority;
|
||||
std::optional<uint32_t> ttlMs;
|
||||
std::set<Network::NetID> networks;
|
||||
std::optional<NetworkMutexEvent> event;
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef TRANSMIT_MESSAGE_H_
|
||||
#define TRANSMIT_MESSAGE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include "icsneo/communication/message/message.h"
|
||||
#include "icsneo/api/eventmanager.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
struct TransmitMessage {
|
||||
static std::vector<uint8_t> EncodeFromMessage(std::shared_ptr<Frame> message, uint32_t client_id, const device_eventhandler_t& report);
|
||||
|
||||
constexpr static size_t messageOptionsOffset = 0;
|
||||
constexpr static size_t messageOptionsSize = 20; // todo determine max
|
||||
constexpr static size_t messageCommonHeaderOffset = messageOptionsOffset + messageOptionsSize;
|
||||
constexpr static size_t messageCommonHeaderSize = 28; // CoreminiMsgExtendedHdr
|
||||
#pragma pack(push,1)
|
||||
struct
|
||||
{
|
||||
uint32_t clientId;
|
||||
uint32_t networkId;
|
||||
uint32_t reserved[3]; // set to 0
|
||||
} options;
|
||||
uint8_t commonHeader[messageCommonHeaderSize];
|
||||
#pragma pack(pop)
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // TRANSMIT_MESSAGE_H_
|
||||
|
|
@ -50,6 +50,9 @@ struct HardwareCANPacket {
|
|||
uint64_t : 3; // Reserved for future status bits
|
||||
uint64_t IsExtended : 1;
|
||||
} timestamp;
|
||||
|
||||
uint16_t NetworkID;
|
||||
uint16_t Length;
|
||||
};
|
||||
struct HardwareCANErrorPacket {
|
||||
uint8_t error_code;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
#include "icsneo/disk/vsa/vsaparser.h"
|
||||
#include "icsneo/communication/message/versionmessage.h"
|
||||
#include "icsneo/communication/message/gptpstatusmessage.h"
|
||||
|
||||
#include "icsneo/communication/message/networkmutexmessage.h"
|
||||
|
||||
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
|
||||
static constexpr DeviceType::Enum DEVICE_TYPE = type; \
|
||||
|
|
@ -856,6 +856,14 @@ public:
|
|||
virtual bool writeMACsecConfig(const MACsecMessage& message, uint16_t binaryIndex);
|
||||
|
||||
std::shared_ptr<DeviceExtension> getExtension(const std::string& name) const;
|
||||
|
||||
[[nodiscard]] std::optional<int> lockNetworks(const std::set<Network::NetID>& networks, uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event);
|
||||
[[nodiscard]] std::optional<int> lockAllNetworks(uint32_t priority, uint32_t ttlMs, NetworkMutexType type, std::function<void(std::shared_ptr<Message>)>&& on_event);
|
||||
bool unlockNetworks(const std::set<Network::NetID>& networks);
|
||||
bool unlockAllNetworks();
|
||||
std::shared_ptr<NetworkMutexMessage> getNetworkMutexStatus(Network::NetID network);
|
||||
|
||||
virtual bool supportsNetworkMutex() const { return false; }
|
||||
|
||||
protected:
|
||||
bool online = false;
|
||||
|
|
@ -969,6 +977,8 @@ protected:
|
|||
};
|
||||
LEDState ledState;
|
||||
void updateLEDState();
|
||||
|
||||
|
||||
private:
|
||||
neodevice_t data;
|
||||
std::shared_ptr<ResetStatusMessage> latestResetStatus;
|
||||
|
|
@ -1127,6 +1137,11 @@ private:
|
|||
|
||||
// Keeponline (keepalive for online)
|
||||
std::unique_ptr<Periodic> keeponline;
|
||||
|
||||
std::optional<uint32_t> assignedClientId;
|
||||
std::set<icsneo::Network::NetID> lockedNetworks;
|
||||
std::optional<int> networkMutexCallbackHandle;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ protected:
|
|||
return 2;
|
||||
}
|
||||
|
||||
bool supportsNetworkMutex() const override { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ protected:
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool supportsNetworkMutex() const override { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ protected:
|
|||
size_t getDiskCount() const override {
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool supportsNetworkMutex() const override { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,3 +50,4 @@ CMAKE_MSVC_RUNTIME_LIBRARY = "MultiThreaded"
|
|||
|
||||
[tool.cibuildwheel]
|
||||
skip = "pp*"
|
||||
environment-pass = ["ICS_IPA_CA_CRT", "LIBICSNEO_ICSPB_REPO"]
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
return readAmount;
|
||||
}
|
||||
|
||||
std::optional<uint64_t> writeLogicalDiskAligned(Communication&, device_eventhandler_t report, uint64_t pos,
|
||||
std::optional<uint64_t> writeLogicalDiskAligned(Communication&, device_eventhandler_t /* report */, uint64_t pos,
|
||||
const uint8_t* from, uint64_t amount, std::chrono::milliseconds, Disk::MemoryType) override {
|
||||
writeCalls++;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue