API: Added icsneoc2.

Signed-off-by: David Rebbe <drebbe@intrepidcs.com>
icsneo_api
David Rebbe 2025-01-24 15:14:58 -05:00
parent c5ba2d8d32
commit 6dd4456f9a
81 changed files with 6731 additions and 364 deletions

View File

@ -12,6 +12,8 @@ option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." O
option(LIBICSNEO_BUILD_EXAMPLES "Build examples." ON)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC2 "Build dynamic C2 library" ON)
option(LIBICSNEO_BUILD_ICSNEOC2_STATIC "Build static C2 library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY_STATIC "Build static icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
@ -28,6 +30,7 @@ option(LIBICSNEO_ENABLE_TCP "Enable devices which communicate over TCP" OFF)
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
option(LIBICSNEO_ENABLE_BINDINGS_PYTHON "Enable Python library" OFF)
option(LIBICSNEO_ENABLE_BINDINGS_RUST "Enable Rust library" OFF)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
@ -334,6 +337,7 @@ endif()
configure_file(api/icsneocpp/buildinfo.h.template ${CMAKE_CURRENT_BINARY_DIR}/generated/buildinfo.h)
configure_file(api/icsneoc/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
configure_file(api/icsneoc2/version.rc.template ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
foreach(EXTINC ${LIBICSNEO_EXTENSION_INCLUDES})
message("Including " ${EXTINC})
@ -461,6 +465,42 @@ if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
target_compile_definitions(icsneoc-static PUBLIC ICSNEOC_BUILD_STATIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOC2)
add_library(icsneoc2 SHARED api/icsneoc2/icsneoc2.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc2/version.rc)
target_include_directories(icsneoc2
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc2 PRIVATE icsneocpp)
target_compile_definitions(icsneoc2
PRIVATE
ICSNEO_EXPORTS _CRT_SECURE_NO_WARNINGS
PUBLIC
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
INTERFACE
ICSNEO_IMPORTS _CRT_SECURE_NO_WARNINGS
)
target_compile_features(icsneoc2 PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc2 PUBLIC ICSNEOC2_BUILD_DYNAMIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOC2_STATIC)
add_library(icsneoc2-static STATIC api/icsneoc2/icsneoc2.cpp)
target_include_directories(icsneoc2-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc2-static PUBLIC icsneocpp)
target_compile_features(icsneoc2-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_definitions(icsneoc2-static PUBLIC ICSNEOC2_BUILD_STATIC)
endif()
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp
@ -527,10 +567,12 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/livedataencoderdecodertest.cpp
test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp
test/unit/icsneoc2.cpp
)
target_link_libraries(libicsneo-unit-tests gtest gtest_main)
target_link_libraries(libicsneo-unit-tests icsneocpp)
target_link_libraries(libicsneo-unit-tests icsneoc2-static)
target_include_directories(libicsneo-unit-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})

View File

@ -0,0 +1,54 @@
#include "icsneo/icsneo.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h"
#include <string>
#include <algorithm>
using namespace icsneo;
struct icsneoOpenOptions_t {
/** Open the device in online mode on open. */
bool goOnlineOnOpen = true;
/** Enable message polling on open. */
bool enablePollingOnOpen = true;
/** Synchronize the device RTC on open.
* Useful for devices that don't have an RTC battery like ValueCAN4 */
bool syncRTCOnOpen = true;
};
typedef struct icsneo_device_t {
// This is the actual device handle, when its not open it will be NULL.
std::shared_ptr<Device> device;
icsneoOpenOptions_t openOptions;
} *icsneo_device_ptr_t;
icsneo_result_t icsneo_find(icsneo_device_ptr_t* devices, uint32_t* devices_count, void* reserved) {
static std::deque<icsneo_device_t> found_icsneo_devices;
if (!devices || !devices_count) {
return icsneo_error_invalid_parameter;
}
// Find all devices and get the minimum size to process
auto found_devices = DeviceFinder::FindAll();
auto min_size = std::minmax(found_devices.size(), static_cast<size_t>(*devices_count)).first;
// lets resize the array to the minimum size
for (auto i = 0; i < min_size; i++) {
const auto* dev = devices[i];
dev = new icsneo_device_t {};
dev->device = found_devices[i];
}
return icsneo_error_success;
}
icsneo_result_t icsneo_open(icsneo_device_ptr_t* device) {
if (!device) {
return icsneo_error_invalid_parameter;
}
return icsneo_error_success;
}

View File

@ -0,0 +1,51 @@
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@
#define VER_FILEVERSION_STR "v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@BUILD_METADATA_PLUS@ @BUILD_GIT_INFO@"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK (VS_FF_DEBUG)
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Intrepid Control Systems, Inc."
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneo.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "OriginalFilename", "icsneo.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END

View File

@ -462,7 +462,7 @@ bool icsneo_transmit(const neodevice_t* device, const neomessage_t* message) {
if(!icsneo_isValidNeoDevice(device))
return false;
if(auto frame = std::dynamic_pointer_cast<icsneo::Frame>(CreateMessageFromNeoMessage(message)))
if(auto frame = std::dynamic_pointer_cast<icsneo::BusMessage>(CreateMessageFromNeoMessage(message)))
return device->device->transmit(frame);
return false;
@ -738,7 +738,7 @@ int icsneo_getDeviceStatus(const neodevice_t* device, void* status, size_t* size
if(!msg) // Did not receive a message
return false;
auto rawMessage = std::static_pointer_cast<RawMessage>(msg);
auto rawMessage = std::static_pointer_cast<InternalMessage>(msg);
if(!rawMessage || (rawMessage->network.getNetID() != Network::NetID::DeviceStatus))
return false;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
#define VER_FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@
#define VER_FILEVERSION_STR "v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@@BUILD_METADATA_PLUS@ @BUILD_GIT_INFO@"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#ifndef DEBUG
#define VER_DEBUG 0
#else
#define VER_DEBUG VS_FF_DEBUG
#endif
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK (VS_FF_DEBUG)
FILEFLAGS (VER_DEBUG)
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Intrepid Control Systems, Inc."
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "icsneo.dll"
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
VALUE "OriginalFilename", "icsneo.dll"
VALUE "ProductName", "libicsneo"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
/* The following line should only be modified for localized versions. */
/* It consists of any number of WORD,WORD pairs, with each pair */
/* describing a language,codepage combination supported by the file. */
/* */
/* For example, a file might have values "0x409,1252" indicating that it */
/* supports English language (0x409) in the Windows ANSI codepage (1252). */
VALUE "Translation", 0x409, 1252
END
END

View File

@ -1,3 +1,18 @@
if(LIBICSNEO_ENABLE_BINDINGS_PYTHON)
add_subdirectory(python)
endif()
if(LIBICSNEO_ENABLE_BINDINGS_RUST)
include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.5 # Optionally specify a commit hash, version tag or branch here
)
FetchContent_MakeAvailable(Corrosion)
corrosion_import_crate(MANIFEST_PATH ${CMAKE_SOURCE_DIR}/bindings/rust/icsneoc2rs/Cargo.toml)
else()
message(STATUS "Not building rust bindings")
endif()

View File

@ -28,6 +28,7 @@ target_link_libraries(icsneopy PRIVATE icsneocpp)
install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND stubgen -m icsneopy -o .)
find_program(STUBGEN stubgen REQUIRED)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND ${STUBGEN} -m icsneopy -o .)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi __init__.py py.typed DESTINATION icsneopy)

View File

@ -7,7 +7,7 @@
namespace icsneo {
void init_canmessage(pybind11::module_& m) {
pybind11::class_<CANMessage, std::shared_ptr<CANMessage>, Frame>(m, "CANMessage")
pybind11::class_<CANMessage, std::shared_ptr<CANMessage>, BusMessage>(m, "CANMessage")
.def(pybind11::init())
.def_readwrite("arbid", &CANMessage::arbid)
.def_readwrite("dlcOnWire", &CANMessage::dlcOnWire)

View File

@ -11,7 +11,7 @@ void init_ethernetmessage(pybind11::module_& m) {
.def("to_string", &MACAddress::toString)
.def("__repr__", &MACAddress::toString);
pybind11::class_<EthernetMessage, std::shared_ptr<EthernetMessage>, Frame>(m, "EthernetMessage")
pybind11::class_<EthernetMessage, std::shared_ptr<EthernetMessage>, BusMessage>(m, "EthernetMessage")
.def(pybind11::init())
.def_readwrite("preemptionEnabled", &EthernetMessage::preemptionEnabled)
.def_readwrite("preemptionFlags", &EthernetMessage::preemptionFlags)

View File

@ -30,7 +30,7 @@ void init_linmessage(pybind11::module_& m) {
.def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered)
.def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly);
pybind11::class_<LINMessage, std::shared_ptr<LINMessage>, Frame> linMessage(m, "LINMessage");
pybind11::class_<LINMessage, std::shared_ptr<LINMessage>, BusMessage> linMessage(m, "LINMessage");
pybind11::enum_<LINMessage::Type>(linMessage, "Type")
.value("NOT_SET", LINMessage::Type::NOT_SET)

View File

@ -7,7 +7,7 @@
namespace icsneo {
void init_mdiomessage(pybind11::module_& m) {
pybind11::class_<MDIOMessage, std::shared_ptr<MDIOMessage>, Frame> mdioMessage(m, "MDIOMessage");
pybind11::class_<MDIOMessage, std::shared_ptr<MDIOMessage>, BusMessage> mdioMessage(m, "MDIOMessage");
pybind11::enum_<MDIOMessage::Clause>(mdioMessage, "Clause")
.value("Clause45", MDIOMessage::Clause::Clause45)
.value("Clause22", MDIOMessage::Clause::Clause22);

View File

@ -9,13 +9,13 @@ namespace icsneo {
void init_message(pybind11::module_& m) {
pybind11::class_<Message, std::shared_ptr<Message>> message(m, "Message");
pybind11::enum_<Message::Type>(message, "Type")
.value("Frame", Message::Type::Frame)
.value("BusMessage", Message::Type::BusMessage)
.value("CANErrorCount", Message::Type::CANErrorCount)
.value("CANError", Message::Type::CANError)
.value("LINHeaderOnly", Message::Type::LINHeaderOnly)
.value("LINBreak", Message::Type::LINBreak)
.value("Invalid", Message::Type::Invalid)
.value("RawMessage", Message::Type::RawMessage)
.value("InternalMessage", Message::Type::InternalMessage)
.value("ReadSettings", Message::Type::ReadSettings)
.value("ResetStatus", Message::Type::ResetStatus)
.value("DeviceVersion", Message::Type::DeviceVersion)
@ -40,14 +40,14 @@ void init_message(pybind11::module_& m) {
message.def_readonly("type", &Message::type);
message.def_readwrite("timestamp", &Message::timestamp);
pybind11::class_<RawMessage, std::shared_ptr<RawMessage>, Message>(m, "RawMessage")
.def_readwrite("network", &RawMessage::network)
.def_readwrite("data", &RawMessage::data);
pybind11::class_<InternalMessage, std::shared_ptr<InternalMessage>, Message>(m, "InternalMessage")
.def_readwrite("network", &InternalMessage::network)
.def_readwrite("data", &InternalMessage::data);
pybind11::class_<Frame, std::shared_ptr<Frame>, RawMessage>(m, "Frame")
.def_readwrite("description", &Frame::description)
.def_readwrite("transmitted", &Frame::transmitted)
.def_readwrite("error", &Frame::error);
pybind11::class_<BusMessage, std::shared_ptr<BusMessage>, InternalMessage>(m, "BusMessage")
.def_readwrite("description", &BusMessage::description)
.def_readwrite("transmitted", &BusMessage::transmitted)
.def_readwrite("error", &BusMessage::error);
}
} // namespace icsneo

View File

@ -28,7 +28,7 @@ void init_device(pybind11::module_& m) {
.def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("add_message_callback", &Device::addMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("remove_message_callback", &Device::removeMessageCallback, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<BusMessage>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference)
.def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference)
.def("get_rtc", &Device::getRTC, pybind11::call_guard<pybind11::gil_scoped_release>())

View File

@ -48,14 +48,10 @@ void init_devicetype(pybind11::module_& m) {
.value("OBD2_PRO", DeviceType::Enum::OBD2_PRO)
.value("ECUChip_UART", DeviceType::Enum::ECUChip_UART)
.value("PLASMA", DeviceType::Enum::PLASMA)
.value("DONT_REUSE0", DeviceType::Enum::DONT_REUSE0)
.value("NEOAnalog", DeviceType::Enum::NEOAnalog)
.value("CT_OBD", DeviceType::Enum::CT_OBD)
.value("DONT_REUSE1", DeviceType::Enum::DONT_REUSE1)
.value("DONT_REUSE2", DeviceType::Enum::DONT_REUSE2)
.value("ION", DeviceType::Enum::ION)
.value("RADStar", DeviceType::Enum::RADStar)
.value("DONT_REUSE3", DeviceType::Enum::DONT_REUSE3)
.value("VCAN4_4", DeviceType::Enum::VCAN4_4)
.value("VCAN4_2", DeviceType::Enum::VCAN4_2)
.value("CMProbe", DeviceType::Enum::CMProbe)

View File

@ -0,0 +1,17 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# RustRover
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

View File

@ -0,0 +1,293 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "bindgen"
version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
]
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "icsneoc2rs"
version = "0.1.0"
dependencies = [
"bindgen",
"scopeguard",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "log"
version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-hash"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@ -0,0 +1,22 @@
[package]
name = "icsneoc2rs"
version = "0.1.0"
edition = "2021"
[lib]
name = "icsneoc2rs"
crate-type = ["rlib", "staticlib", "cdylib"]
path = "src/lib.rs"
[[example]]
name = "simple"
path = "examples/simple.rs"
[dev-dependencies]
scopeguard = "1.2.0"
[features]
static = []
[build-dependencies]
bindgen = "0.71.1"

View File

@ -0,0 +1,40 @@
use std::env;
use std::path::PathBuf;
pub fn main() {
// Tell cargo to look for shared libraries in the specified directory
println!("cargo:rustc-link-search=../../../build");
// Tell cargo to tell rustc to link the system
// shared library.
println!("cargo:rustc-link-lib=icsneoc2");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("../../../include/icsneo/icsneoc2.h")
.clang_arg("-I../../../include")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.derive_default(true)
.derive_debug(true)
.derive_partialeq(true)
.derive_copy(true)
.default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true })
.default_alias_style(bindgen::AliasVariation::TypeAlias)
.generate_cstr(true)
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}

View File

@ -0,0 +1,333 @@
use icsneoc2rs::ffi::_icsneoc2_msg_bus_type_t::*;
use icsneoc2rs::ffi::_icsneoc2_msg_type_t::*;
use icsneoc2rs::ffi::_icsneoc2_netid_t;
use icsneoc2rs::ffi::_icsneoc2_netid_t::*;
use icsneoc2rs::ffi::_icsneoc2_open_options_t::*;
use icsneoc2rs::ffi::icsneoc2_message_t;
use icsneoc2rs::ffi::icsneoc2_msg_bus_type_t;
use icsneoc2rs::ffi::icsneoc2_msg_type_t;
use icsneoc2rs::ffi::icsneoc2_netid_t;
use icsneoc2rs::Device;
use icsneoc2rs::Error;
use icsneoc2rs::Result as ICSNeoResult;
use scopeguard::defer;
fn main() -> ICSNeoResult<()> {
print!("Finding devices... ");
let devices = Device::find_all(255)?;
println!(
"OK, {} device{} found...",
devices.len(),
if devices.len() > 1 { "s" } else { "" }
);
for device in devices {
device.device_is_valid()?;
// Get description of the device
let description = match device.device_description_get() {
Ok(description) => description,
Err(err) => {
println!("Failed to get description of device: {err}");
continue;
}
};
println!("{} @ Handle {:?}", description, device.handle);
// Get/Set open options
let mut open_options = match device.device_open_options_get() {
Ok(value) => value,
Err(err) => {
println!("Failed to get open options of device: {err}");
continue;
}
};
// Disable Syncing RTC and going online
open_options &= !(icsneoc2_open_options_sync_rtc as u32);
open_options &= !(icsneoc2_open_options_go_online as u32);
match device.device_open_options_set(open_options) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("\tDevice open options: {open_options:#02x}");
// Open the device
print!("\tOpening device... ");
match device.device_open() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
defer! {
print_device_events(&device, &description).expect("Critical: Failed to print device events");
}
// Get timestamp resolution of the device
print!("\tGetting timestamp resolution... ");
let timestamp_resolution = match device.device_timestamp_resolution_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{timestamp_resolution}ns");
// Get baudrates for HSCAN
print!("\tGetting HSCAN baudrate... ");
let baudrate = match device.device_baudrate_get(icsneoc2_netid_hscan) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{baudrate}mbit/s");
// Get FD baudrates for HSCAN
print!("\tGetting FD HSCAN baudrate... ");
let fd_baudrate = match device.device_canfd_baudrate_get(icsneoc2_netid_hscan) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{fd_baudrate}mbit/s");
// Set baudrates for HSCAN
// saveToDevice: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
print!("\tSetting HSCAN baudrate... ");
let save_to_device = false;
match device.device_baudrate_set(icsneoc2_netid_hscan, baudrate, save_to_device) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Set FD baudrates for HSCAN
print!("\tSetting FD HSCAN baudrate... ");
match device.device_canfd_baudrate_set(icsneoc2_netid_hscan, fd_baudrate, save_to_device) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Get RTC
print!("\tGetting RTC... ");
let current_rtc = match device.device_rtc_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{current_rtc}");
// Set RTC
print!("\tSetting RTC... ");
match device.device_rtc_set(current_rtc) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
// Get RTC
print!("\tGetting RTC... ");
let rtc = match device.device_rtc_get() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{rtc}");
// Go online, start acking traffic
print!("\tGoing online... ");
match device.device_go_online(true) {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
let is_online = match device.device_is_online() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("{}", if is_online { "Online" } else { "Offline" });
// Transmit CAN messages
if transmit_can_messages(&device).is_err() {
continue;
}
println!("\tWaiting 1 second for messages...");
std::thread::sleep(std::time::Duration::from_secs(1));
// Get the messages
let messages = match device.device_messages_get(20000, 3000) {
Ok(messages) => messages,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
// Process the messages
if process_messages(&device, messages).is_err() {
continue;
}
// Close the device
print!("\tClosing device... ");
match device.device_close() {
Ok(value) => value,
Err(err) => {
print_error(&device, &description, err);
continue;
}
};
println!("OK");
}
Ok(())
}
fn print_error(device: &Device, device_description: &String, err: Error) {
println!("Failed: {err}");
print_device_events(device, device_description)
.expect("Critical: Failed to print device events");
}
fn transmit_can_messages(device: &Device) -> ICSNeoResult<()> {
const MESSAGE_COUNT: usize = 100;
println!("\tTransmitting {MESSAGE_COUNT} messages...");
for i in 0..MESSAGE_COUNT {
let message = match device.message_can_create(1) {
Ok(messages) => messages[0],
Err(err) => {
println!("Failed to create CAN message #{i}: {err}");
continue;
}
};
device.message_netid_set(message, icsneoc2_netid_hscan)?;
device.message_can_arbid_set(message, 0x10)?;
device.message_can_canfd_set(message, true)?;
device.message_can_extended_set(message, true)?;
device.message_can_baudrate_switch_set(message, true)?;
device.message_data_set(
message,
vec![
(i >> 56 & 0xFF) as u8,
(i >> 48 & 0xFF) as u8,
(i >> 40 & 0xFF) as u8,
(i >> 32 & 0xFF) as u8,
(i >> 24 & 0xFF) as u8,
(i >> 16 & 0xFF) as u8,
(i >> 8 & 0xFF) as u8,
(i & 0xFF) as u8,
],
)?;
device.message_can_dlc_set(message, -1)?;
device.device_messages_transmit(vec![message])?;
}
Ok(())
}
fn process_messages(device: &Device, messages: Vec<*mut icsneoc2_message_t>) -> ICSNeoResult<()> {
let mut tx_count: u32 = 0;
for (i, message) in messages.iter().enumerate() {
// Get the message type
let msg_type = device.message_type_get(*message)?;
// Get the message type name
let msg_type_name = device.message_type_name_get(msg_type)?;
// Check if the message is a bus message, ignore otherwise
if msg_type != icsneoc2_msg_type_bus as icsneoc2_msg_type_t {
println!("\tIgnoring message type : {msg_type} ({msg_type_name})");
continue;
}
// Get the message bus type
let msg_bus_type = device.message_bus_type_get(*message)?;
// Get the message type name
let msg_bus_type_name = device.bus_type_name_get(msg_bus_type)?;
// Check if message is a transmit message
if device.message_is_transmit(*message)? {
tx_count += 1;
continue;
}
println!("\t{i} Message type: {msg_type} bus type: {msg_bus_type_name} ({msg_bus_type})\n");
// Check if the message is a CAN message, ignore otherwise
if msg_bus_type == icsneoc2_msg_bus_type_can as icsneoc2_msg_bus_type_t {
let netid = device.message_netid_get(*message)?;
let netid_name = device.netid_name_get(netid)?;
let arbid = device.message_can_arbid_get(*message)?;
let dlc = device.message_can_dlc_get(*message)?;
let is_remote = device.message_can_is_remote(*message)?;
let is_canfd = device.message_can_is_canfd(*message)?;
let is_extended = device.message_can_is_extended(*message)?;
let data = device.message_data_get(*message, 64)?;
// Finally lets print the RX message
println!("\t NetID: {netid_name} ({:#02x})\tArbID: {arbid:#02x}\t DLC: {dlc}\t Remote: {is_remote}\t \
CANFD: {is_canfd}\t Extended: {is_extended}\t Data length: {}\n", netid as icsneoc2_netid_t,data.len());
println!("\t Data: {data:#02x?}\n");
} else {
println!("\tIgnoring bus message type: {msg_bus_type} ({msg_bus_type_name})\n");
}
}
println!(
"\tReceived {} messages total, {} were TX messages",
messages.len(),
tx_count
);
Ok(())
}
fn print_device_events(device: &Device, device_description: &String) -> ICSNeoResult<()> {
let events = match device.device_events_get(1024) {
Ok(events) => events,
Err(err) => {
println!("Failed to get device events: {err}");
return Err(err);
}
};
for (i, event) in events.iter().enumerate() {
let description = match device.event_description_get(*event) {
Ok(description) => description,
Err(err) => {
println!("Failed to get event description: {err}");
continue;
}
};
println!("\t{device_description}: Event {i}: {description}");
}
// Get global events
let global_events = match device.events_get(1024) {
Ok(events) => events,
Err(err) => {
println!("Failed to get global events: {err}");
return Err(err);
}
};
for (i, event) in global_events.iter().enumerate() {
let description = match device.event_description_get(*event) {
Ok(description) => description,
Err(err) => {
println!("Failed to get event description: {err}");
continue;
}
};
println!("\t{device_description}: Global Event {i}: {description}");
}
println!(
"\t{device_description}: Received {} events and {} global events\n",
events.len(),
global_events.len()
);
Ok(())
}

View File

@ -0,0 +1,5 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View File

@ -0,0 +1,902 @@
pub mod ffi;
use ffi::_icsneoc2_error_t::{icsneoc2_error_invalid_device, icsneoc2_error_success};
use ffi::_icsneoc2_open_options_t::*;
use ffi::*;
use std::ffi::CString;
use std::fmt::Display;
#[derive(Debug, Clone)]
pub enum Error {
/// icsneoc2 API error
APIError(icsneoc2_error_t, String),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::APIError(error_code, error_string) => write!(f, "API Error: \"{}\" ({})", error_string, error_code),
}
}
}
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub struct Device {
/// Handle to the device.
pub handle: *mut icsneoc2_device_t,
}
impl Drop for Device {
fn drop(&mut self) {
// Make sure the device is closed before we go out of scope.
self.device_close().expect("Failed to close device!");
}
}
impl Device {
pub fn find_all(device_count: u32) -> Result<Vec<Self>> {
// Find all the devices
const MAX_DEVICE_COUNT: u32 = 255;
let mut devices: [*mut icsneoc2_device_t; MAX_DEVICE_COUNT as usize] =
[std::ptr::null_mut(); 255];
let mut devices_count: u32 = if device_count > MAX_DEVICE_COUNT {
MAX_DEVICE_COUNT
} else {
device_count
};
let res = unsafe {
icsneoc2_device_find_all(
devices.as_mut_ptr(),
&mut devices_count as *mut u32,
std::ptr::null_mut(),
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Return the results
let found_devices: Vec<Self> = devices[..devices_count as usize]
.iter()
.map(|d| Self { handle: *d })
.collect();
Ok(found_devices)
}
pub fn bus_type_name_get(&self, bus_type: icsneoc2_msg_bus_type_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_bus_type_name_get(bus_type, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_baudrate_get(&self, netid: _icsneoc2_netid_t) -> Result<u64> {
let mut value: u64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_baudrate_get(self.handle, netid as icsneoc2_netid_t, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_baudrate_set(
&self,
netid: _icsneoc2_netid_t,
value: u64,
save: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_baudrate_set(self.handle, netid as icsneoc2_netid_t, value, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_canfd_baudrate_get(&self, netid: _icsneoc2_netid_t) -> Result<u64> {
let mut value: u64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_canfd_baudrate_get(self.handle, netid as icsneoc2_netid_t, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_canfd_baudrate_set(
&self,
netid: _icsneoc2_netid_t,
value: u64,
save: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_canfd_baudrate_set(self.handle, netid as icsneoc2_netid_t, value, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_close(&self) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_close(self.handle) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_description_get(&self) -> Result<String> {
// Get the error code
let mut description: Vec<u8> = vec![0; 255];
let mut description_length: u32 = 255;
let res = unsafe {
icsneoc2_device_description_get(
self.handle,
description.as_mut_ptr() as *mut i8,
&mut description_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
description.resize(description_length as usize, 0);
let description_str = {
CString::new(description)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(description_str)
}
pub fn device_events_get(&self, event_count: u32) -> Result<Vec<*mut icsneoc2_event_t>> {
let mut events: Vec<*mut icsneoc2_event_t> =
vec![std::ptr::null_mut(); event_count as usize];
let mut event_count: u32 = event_count;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_events_get(self.handle, events.as_mut_ptr(), &mut event_count)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
events.resize(event_count as usize, std::ptr::null_mut());
Ok(events)
}
pub fn device_go_online(&self, go_online: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_go_online(self.handle, go_online) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_is_online(&self) -> Result<bool> {
let mut is_online: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_online(self.handle, &mut is_online) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_online)
}
pub fn device_is_online_supported(&self) -> Result<bool> {
let mut is_online_supported: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_is_online_supported(self.handle, &mut is_online_supported)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_online_supported)
}
pub fn device_is_valid(&self) -> Result<bool> {
let res: icsneoc2_error_t = unsafe { icsneoc2_device_is_valid(self.handle) };
match res {
res if res == icsneoc2_error_success as icsneoc2_error_t => Ok(true),
res if res == icsneoc2_error_invalid_device as icsneoc2_error_t => Ok(false),
_ => Err(Self::error_code_get(res)),
}
}
pub fn device_is_open(&self) -> Result<bool> {
let mut is_open: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_open(self.handle, &mut is_open) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_open)
}
pub fn device_is_disconnected(&self) -> Result<bool> {
let mut is_disconnected: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_is_disconnected(self.handle, &mut is_disconnected) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(is_disconnected)
}
pub fn device_load_default_settings(&self, save: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_load_default_settings(self.handle, save) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_message_count_get(&self) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_count_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_get(&self) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_limit_get(&self) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_limit_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_message_polling_set(&self, enable: bool) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_set(self.handle, enable) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_message_polling_set_limit(&self, value: u32) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_message_polling_set_limit(self.handle, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_messages_get(
&self,
message_count: u32,
timeout_ms: u32,
) -> Result<Vec<*mut icsneoc2_message_t>> {
let mut messages: Vec<*mut icsneoc2_message_t> =
vec![std::ptr::null_mut(); message_count as usize];
let mut message_count: u32 = message_count;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_messages_get(
self.handle,
messages.as_mut_ptr(),
&mut message_count,
timeout_ms,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
messages.resize(message_count as usize, std::ptr::null_mut());
Ok(messages)
}
pub fn device_messages_transmit(&self, messages: Vec<*mut icsneoc2_message_t>) -> Result<u32> {
let mut messages_count: u32 = messages.len() as u32;
let mut messages = messages;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_messages_transmit(
self.handle,
messages.as_mut_ptr(),
&mut messages_count,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(messages_count)
}
pub fn device_open(&self) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_open(self.handle) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_open_options_get(&self) -> Result<ffi::icsneoc2_open_options_t> {
let mut open_options: ffi::icsneoc2_open_options_t =
icsneoc2_open_options_none as ffi::icsneoc2_open_options_t;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_open_options_get(self.handle, &mut open_options) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(open_options)
}
pub fn device_open_options_set(
&self,
open_options: ffi::icsneoc2_open_options_t,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_open_options_set(self.handle, open_options) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_rtc_get(&self) -> Result<i64> {
let mut value: i64 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_rtc_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_rtc_set(&self, value: i64) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_device_rtc_set(self.handle, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn device_serial_get(&self) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_device_serial_get(self.handle, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_supports_tc10(&self) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_supports_tc10(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn device_timestamp_resolution_get(&self) -> Result<u32> {
let mut timestamp_resolution: u32 = 0;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_device_timestamp_resolution_get(self.handle, &mut timestamp_resolution)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(timestamp_resolution)
}
pub fn device_type_from_type(&self, device_type: icsneoc2_devicetype_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_device_type_name_get(
device_type,
str.as_mut_ptr() as *mut i8,
&mut str_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn device_type_get(&self) -> Result<icsneoc2_devicetype_t> {
let mut value: icsneoc2_devicetype_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_device_type_get(self.handle, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn error_code_get(error_code: icsneoc2_error_t) -> Error {
// Get the error code
let mut error_description: Vec<u8> = vec![0; 255];
let mut error_description_length: u32 = 255;
let res = unsafe {
icsneoc2_error_code_get(
error_code,
error_description.as_mut_ptr() as *mut i8,
&mut error_description_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Error::APIError(res, "icsneoc2_error_code_get() failed.".to_string());
}
// Convert the vec to an String
error_description.resize(error_description_length as usize, 0);
let error_str = CString::new(error_description)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string");
Error::APIError(error_code, error_str)
}
pub fn event_description_get(&self, event: *mut icsneoc2_event_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_event_description_get(event, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn events_get(&self, event_count: u32) -> Result<Vec<*mut icsneoc2_event_t>> {
let mut events: Vec<*mut icsneoc2_event_t> =
vec![std::ptr::null_mut(); event_count as usize];
let mut event_count: u32 = event_count;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_events_get(events.as_mut_ptr(), &mut event_count) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
events.resize(event_count as usize, std::ptr::null_mut());
Ok(events)
}
pub fn message_bus_type_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<icsneoc2_msg_bus_type_t> {
let mut value: icsneoc2_msg_bus_type_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_bus_type_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_arbid_get(&self, message: *mut icsneoc2_message_t) -> Result<u32> {
let mut value: u32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_arbid_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_arbid_set(
&self,
message: *mut icsneoc2_message_t,
value: u32,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_arbid_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_baudrate_switch_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_baudrate_switch_get(self.handle, message, &mut value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_baudrate_switch_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_baudrate_switch_set(self.handle, message, value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_canfd_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_canfd_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_create(&self, message_count: u32) -> Result<Vec<*mut icsneoc2_message_t>> {
let mut messages: Vec<*mut icsneoc2_message_t> =
vec![std::ptr::null_mut(); message_count as usize];
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_create(self.handle, messages.as_mut_ptr(), message_count)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(messages)
}
pub fn message_can_dlc_get(&self, message: *mut icsneoc2_message_t) -> Result<i32> {
let mut value: i32 = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_dlc_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_dlc_set(&self, message: *mut icsneoc2_message_t, value: i32) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_dlc_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_error_state_indicator_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_can_error_state_indicator_get(self.handle, message, &mut value)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_extended_set(
&self,
message: *mut icsneoc2_message_t,
value: bool,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_extended_set(self.handle, message, value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_free(&self, message: *mut icsneoc2_message_t) -> Result<()> {
let res: icsneoc2_error_t = unsafe { ffi::icsneoc2_message_can_free(self.handle, message) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_can_is_canfd(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_canfd(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_is_extended(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_extended(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_can_is_remote(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_can_is_remote(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_data_get(
&self,
message: *mut icsneoc2_message_t,
data_length: u32,
) -> Result<Vec<u8>> {
let mut data: Vec<u8> = vec![0; data_length as usize];
let mut data_length = data_length;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_data_get(
self.handle,
message,
data.as_mut_ptr(),
&mut data_length,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
data.resize(data_length as usize, 0);
Ok(data)
}
pub fn message_data_set(&self, message: *mut icsneoc2_message_t, data: Vec<u8>) -> Result<()> {
let mut data = data;
let res: icsneoc2_error_t = unsafe {
ffi::icsneoc2_message_data_set(
self.handle,
message,
data.as_mut_ptr(),
data.len() as u32,
)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_is_transmit(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_is_transmit(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_is_valid(&self, message: *mut icsneoc2_message_t) -> Result<bool> {
let mut value: bool = false;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_is_valid(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_netid_get(&self, message: *mut icsneoc2_message_t) -> Result<_icsneoc2_netid_t> {
let mut value: icsneoc2_netid_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_netid_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// TODO: This is gross, there is probably a better way to do this.
// TryFrom impl would be a lot of work to implement because there are so many values.
// We are relying on the function call to always return a valid value.
let value: _icsneoc2_netid_t = unsafe { std::mem::transmute(value as u32) };
Ok(value)
}
pub fn message_netid_set(
&self,
message: *mut icsneoc2_message_t,
value: _icsneoc2_netid_t,
) -> Result<()> {
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_netid_set(self.handle, message, value as icsneoc2_netid_t) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(())
}
pub fn message_type_get(
&self,
message: *mut icsneoc2_message_t,
) -> Result<icsneoc2_msg_type_t> {
let mut value: icsneoc2_msg_type_t = 0;
let res: icsneoc2_error_t =
unsafe { ffi::icsneoc2_message_type_get(self.handle, message, &mut value) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
Ok(value)
}
pub fn message_type_name_get(&self, msg_type: icsneoc2_msg_type_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res = unsafe {
icsneoc2_message_type_name_get(msg_type, str.as_mut_ptr() as *mut i8, &mut str_length)
};
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
pub fn netid_name_get(&self, netid: _icsneoc2_netid_t) -> Result<String> {
// Get the string
let mut str: Vec<u8> = vec![0; 255];
let mut str_length: u32 = 255;
let res =
unsafe { icsneoc2_netid_name_get(netid as icsneoc2_netid_t, str.as_mut_ptr() as *mut i8, &mut str_length) };
// Check the error code
if res != icsneoc2_error_success as icsneoc2_error_t {
return Err(Self::error_code_get(res));
}
// Convert the vec to an String
str.resize(str_length as usize, 0);
let str_string = {
CString::new(str)
.expect("CString::new failed")
.into_string()
.expect("CString::new::into_string")
};
Ok(str_string)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_device_find_all() {
let devices = Device::find_all(0).unwrap();
assert_eq!(devices.len(), 0);
}
}

View File

@ -89,7 +89,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result->timestamp *= timestampResolution;
switch(result->type) {
case Message::Type::Frame: {
case Message::Type::BusMessage: {
CANMessage& can = *static_cast<CANMessage*>(result.get());
can.network = packet->network;
break;
@ -233,7 +233,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// They come in as CAN but we will handle them in the device rather than
// passing them onto the user.
if(packet->data.size() < 24) {
auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device);
auto rawmsg = std::make_shared<InternalMessage>(Network::NetID::Device);
result = rawmsg;
rawmsg->data = packet->data;
return true;
@ -263,7 +263,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
}
case Network::NetID::DeviceStatus: {
// Just pass along the data, the device needs to handle this itself
result = std::make_shared<RawMessage>(packet->network, packet->data);
result = std::make_shared<InternalMessage>(packet->network, packet->data);
return true;
}
case Network::NetID::RED_INT_MEMORYREAD: {
@ -324,7 +324,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true;
}
default:
// No defined handler, treat this as a RawMessage
// No defined handler, treat this as a InternalMessage
break;
}
break;
@ -499,6 +499,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
}
// For the moment other types of messages will automatically be decoded as raw messages
result = std::make_shared<RawMessage>(packet->network, packet->data);
result = std::make_shared<InternalMessage>(packet->network, packet->data);
return true;
}

View File

@ -23,8 +23,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
result.clear();
switch(message->type) {
case Message::Type::Frame: {
auto frame = std::dynamic_pointer_cast<Frame>(message);
case Message::Type::BusMessage: {
auto frame = std::dynamic_pointer_cast<BusMessage>(message);
// Frame uses frame->data as the buffer unless directed otherwise
buffer = &frame->data;
@ -130,8 +130,8 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
break;
}
case Message::Type::RawMessage: {
auto raw = std::dynamic_pointer_cast<RawMessage>(message);
case Message::Type::InternalMessage: {
auto raw = std::dynamic_pointer_cast<InternalMessage>(message);
// Raw message uses raw->data as the buffer unless directed otherwise
buffer = &raw->data;
@ -243,7 +243,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
* In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else.
*/
auto canmsg = std::make_shared<RawMessage>(Network::NetID::Device);
auto canmsg = std::make_shared<InternalMessage>(Network::NetID::Device);
msg = canmsg;
if(arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);

View File

@ -102,11 +102,11 @@ bool A2BWAVOutput::callIfMatch(const std::shared_ptr<Message>& message) const {
return false;
}
if(message->type != Message::Type::Frame) {
if(message->type != Message::Type::BusMessage) {
return false;
}
const auto& frameMsg = std::dynamic_pointer_cast<Frame>(message);
const auto& frameMsg = std::dynamic_pointer_cast<BusMessage>(message);
if(!frameMsg) {
return false;

View File

@ -14,9 +14,9 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
neomsg.timestamp = message->timestamp;
switch (message->type)
{
case Message::Type::Frame: {
case Message::Type::BusMessage: {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<Frame>(message);
auto framemsg = std::static_pointer_cast<BusMessage>(message);
const auto netType = framemsg->network.getType();
frame.netid = (neonetid_t)framemsg->network.getNetID();
@ -120,7 +120,7 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
switch((Message::Type)neomessage->messageType) {
case Message::Type::Frame: {
case Message::Type::BusMessage: {
const Network network = ((neomessage_frame_t*)neomessage)->netid;
switch(network.getType()) {
case Network::Type::CAN:

View File

@ -3,7 +3,7 @@
using namespace icsneo;
static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
std::optional<uint8_t> icsneo::CAN_DLCToLength(uint8_t length, bool fd) {
if (length <= 8)
return length;
@ -29,7 +29,7 @@ static std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
return std::nullopt;
}
static std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
std::optional<uint8_t> icsneo::CAN_LengthToDLC(size_t dataLength, bool fd)
{
if (dataLength <= 8)
return uint8_t(dataLength);

View File

@ -480,7 +480,7 @@ int8_t Device::prepareScriptLoad() {
return false;
}
const auto resp = std::static_pointer_cast<RawMessage>(generic);
const auto resp = std::static_pointer_cast<InternalMessage>(generic);
retVal = (int8_t)resp->data[0];
}
@ -743,7 +743,7 @@ std::optional<CoreminiHeader> Device::readCoreminiHeader(Disk::MemoryType memTyp
return ret;
}
bool Device::transmit(std::shared_ptr<Frame> frame) {
bool Device::transmit(std::shared_ptr<BusMessage> frame) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
@ -776,7 +776,7 @@ bool Device::transmit(std::shared_ptr<Frame> frame) {
return com->sendPacket(packet);
}
bool Device::transmit(std::vector<std::shared_ptr<Frame>> frames) {
bool Device::transmit(std::vector<std::shared_ptr<BusMessage>> frames) {
for(auto& frame : frames) {
if(!transmit(frame))
return false;
@ -1721,8 +1721,8 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
case Message::Type::ResetStatus:
latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message);
break;
case Message::Type::RawMessage: {
auto rawMessage = std::static_pointer_cast<RawMessage>(message);
case Message::Type::InternalMessage: {
auto rawMessage = std::static_pointer_cast<InternalMessage>(message);
switch(rawMessage->network.getNetID()) {
case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves
@ -1733,8 +1733,8 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
}
break;
}
case Message::Type::Frame: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
case Message::Type::BusMessage: {
// Device is not guaranteed to be a CANMessage, it might be a InternalMessage
// 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);
@ -1898,7 +1898,7 @@ std::optional<std::chrono::time_point<std::chrono::system_clock>> Device::getRTC
if(!generic) // Did not receive a message
return std::nullopt;
auto rawMes = std::dynamic_pointer_cast<RawMessage>(generic);
auto rawMes = std::dynamic_pointer_cast<InternalMessage>(generic);
if(!rawMes)
return std::nullopt;

View File

@ -45,7 +45,7 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
}
}
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) {
bool FlexRay::Extension::transmitHook(const std::shared_ptr<BusMessage>& frame, bool& success) {
if(!frame || frame->network.getType() != Network::Type::FlexRay)
return true; // Don't hook non-FlexRay messages

View File

@ -1,6 +1,7 @@
option(LIBICSNEO_BUILD_C_INTERACTIVE_EXAMPLE "Build the command-line interactive C example." ON)
option(LIBICSNEO_BUILD_C_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE "Build the command-line simple C example." ON)
option(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE "Build the simple C++ example." ON)
option(LIBICSNEO_BUILD_CPP_INTERACTIVE_EXAMPLE "Build the command-line interactive C++ example." ON)
option(LIBICSNEO_BUILD_CPP_A2B_EXAMPLE "Build the A2B example." ON)
@ -27,6 +28,10 @@ if(LIBICSNEO_BUILD_C_LEGACY_EXAMPLE)
add_subdirectory(c/legacy)
endif()
if(LIBICSNEO_BUILD_C2_SIMPLE_EXAMPLE)
add_subdirectory(c2/simple)
endif()
if(LIBICSNEO_BUILD_CPP_SIMPLE_EXAMPLE)
add_subdirectory(cpp/simple)
endif()

View File

@ -0,0 +1,2 @@
add_executable(libicsneo-simple-example src/main.c)
target_link_libraries(libicsneo-simple-example icsneoc2)

View File

@ -0,0 +1,454 @@
#include <icsneo/icsneoc2.h>
#include <stdio.h>
#include <time.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <unistd.h>
#endif
/**
* @brief Sleeps for a specified number of milliseconds.
*
* Sleeps for a specified number of milliseconds using Sleep() on Windows and sleep() on *nix.
*
* @param ms The number of milliseconds to sleep.
*/
void sleep_ms(uint32_t ms) {
#if defined(_WIN32) || defined(_WIN64)
Sleep(ms);
#else
sleep(ms / 1000);
#endif
}
/**
* @brief Prints an error message with the given string and error code.
*
* If the error code is not icsneoc2_error_success, prints the error string for the given error code
* and returns the error code.
*
* @param message The message to print.
* @param error The error code to print.
* @return error as int
*/
int print_error_code(const char* message, icsneoc2_error_t error) {
char error_str[256] = {0};
uint32_t error_length = 256;
icsneoc2_error_t res = icsneoc2_error_code_get(error, error_str, &error_length);
if (res != icsneoc2_error_success) {
printf("%s: Failed to get string for error code %d with error code %d\n", message, error, res);
return res;
}
printf("%s: \"%s\" (%u)\n", message, error_str, error);
return (int)error;
}
/**
* @brief Processes a list of messages from a device.
*
* This function iterates over a given array of messages received from a specified device.
* For each message in the array, it retrieves and prints the message type and bus type.
* If an error occurs while retrieving these details, an error message is printed.
*
* @param device A pointer to the icsneoc2_device_t structure representing the device.
* @param messages An array of pointers to icsneoc2_message_t structures containing the messages to process.
* @param messages_count The number of messages in the messages array.
*
* @return An icsneoc2_error_t value indicating success or failure of the message processing.
*/
int process_messages(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count);
/**
* @brief Prints device and global events for a given device.
*
* This function retrieves and prints all current events associated with the specified device,
* as well as any global events not tied to a specific device. For each event, it retrieves
* and prints a description. If retrieving events or their descriptions fails, an error
* message is printed. The function also prints a summary of the count of device-specific
* and global events processed.
*
* @param device A pointer to the icsneoc2_device_t structure representing the device to get events from.
* @param device_description A description of the device used in the output.
*/
void print_device_events(icsneoc2_device_t* device, const char* device_description);
/**
* @brief Transmits a series of CAN messages from a device.
*
* This function creates and transmits 100 CAN messages with incrementing payload data.
* Each message is configured with specific attributes such as network ID, arbitration
* ID, CANFD status, extended status, and baudrate switch. After successfully transmitting
* each message, it is freed from memory.
*
* @param device A pointer to the icsneoc2_device_t structure representing the device to transmit messages from.
*
* @return An icsneoc2_error_t value indicating success or failure of the message transmission process.
*/
int transmit_can_messages(icsneoc2_device_t* device);
/**
* @brief Get the RTC (Real time clock) of a device and print it.
*
* @param[in] device The device to get the RTC of.
* @param[in] description A description of the device for printing purpose.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device, const char* description);
int main(int argc, char* argv[]) {
(void)argc;
(void)argv;
icsneoc2_device_t* devices[255] = {0};
uint32_t devices_count = 255;
printf("Finding devices...\n");
icsneoc2_error_t res = icsneoc2_device_find_all(devices, &devices_count, NULL);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to find devices", res);
};
printf("OK, %u device%s found\n", devices_count, devices_count == 1 ? "" : "s");
// List off the devices
for (uint32_t i = 0; i < devices_count; i++) {
icsneoc2_device_t* device = devices[i];
// Get description of the device
const char description[255] = {0};
uint32_t description_length = 255;
res = icsneoc2_device_description_get(device, description, &description_length);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get device description", res);
};
printf("%.*s @ Handle %p\n", description_length, description, device);
// Get/Set open options
icsneoc2_open_options_t options = icsneoc2_open_options_none;
res = icsneoc2_device_open_options_get(device, &options);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get open options", res);
}
// Disable Syncing RTC and going online
options &= ~icsneoc2_open_options_sync_rtc;
options &= ~icsneoc2_open_options_go_online;
printf("\tDevice open options: 0x%x\n", options);
res = icsneoc2_device_open_options_set(device, options);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set open options", res);
}
// Open the device
printf("\tOpening device: %s...\n", description);
res = icsneoc2_device_open(device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to open device", res);
};
// Get timestamp resolution of the device
printf("\tGetting timestamp resolution... ");
uint32_t timestamp_resolution = 0;
res = icsneoc2_device_timestamp_resolution_get(device, &timestamp_resolution);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get timestamp resolution", res);
}
printf("%uns\n", timestamp_resolution);
// Get baudrates for HSCAN
printf("\tGetting HSCAN Baudrate... ");
uint64_t baudrate = 0;
res = icsneoc2_device_baudrate_get(device, icsneoc2_netid_hscan, &baudrate);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get baudrate", res);
};
printf("%llumbit/s\n", baudrate);
// Get FDbaudrates for HSCAN
printf("\tGetting FD HSCAN Baudrate... ");
uint64_t fd_baudrate = 0;
res = icsneoc2_device_canfd_baudrate_get(device, icsneoc2_netid_hscan, &fd_baudrate);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get FD baudrate", res);
};
printf("%llumbit/s\n", fd_baudrate);
// Set baudrates for HSCAN
// save_to_device: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
bool save_to_device = false;
printf("\tSetting HSCAN Baudrate... ");
res = icsneoc2_device_baudrate_set(device, icsneoc2_netid_hscan, baudrate, save_to_device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set baudrate", res);
};
printf("Ok\n");
// Set FDbaudrates for HSCAN
printf("\tSetting FD HSCAN Baudrate... ");
res = icsneoc2_device_canfd_baudrate_set(device, icsneoc2_netid_hscan, fd_baudrate, save_to_device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set FD baudrate", res);
};
printf("Ok\n");
// Get RTC
printf("\tGetting RTC... ");
res = get_and_print_rtc(device, description);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get RTC", res);
}
// Set RTC
printf("\tSetting RTC to current time... ");
time_t current_time = time(NULL);
res = icsneoc2_device_rtc_set(device, current_time);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to set RTC", res);
}
printf("Ok\n");
// Get RTC
printf("\tGetting RTC... ");
res = get_and_print_rtc(device, description);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get RTC", res);
}
// Go online, start acking traffic
printf("\tGoing online... ");
res = icsneoc2_device_go_online(device, true);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to go online", res);
}
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
bool is_online = false;
res = icsneoc2_device_is_online(device, &is_online);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to check if online", res);
}
printf("%s\n", is_online ? "Online" : "Offline");
// Transmit CAN messages
res = transmit_can_messages(device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to transmit CAN messages", res);
}
// Wait for the bus to collect some messages, requires an active bus to get messages
printf("\tWaiting 1 second for messages...\n");
sleep_ms(1000);
// Get the messages
icsneoc2_message_t* messages[20000] = {0};
uint32_t message_count = 20000;
printf("\tGetting messages from device with timeout of 3000ms on %s...\n", description);
res = icsneoc2_device_messages_get(device, messages, &message_count, 3000);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to get messages from device", res);
};
// Process the messages
res = process_messages(device, messages, message_count);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to process messages", res);
}
// Finally, close the device.
printf("\tClosing device: %s...\n", description);
res = icsneoc2_device_close(device);
if (res != icsneoc2_error_success) {
print_device_events(device, description);
return print_error_code("\tFailed to close device", res);
};
// Print device events
print_device_events(device, description);
}
printf("\n");
return 0;
}
icsneoc2_error_t get_and_print_rtc(icsneoc2_device_t* device, const char* description) {
time_t unix_epoch = 0;
icsneoc2_error_t res = icsneoc2_device_rtc_get(device, &unix_epoch);
if (res != icsneoc2_error_success) {
return res;
}
char rtc_time[32] = {0};
strftime(rtc_time, sizeof(rtc_time), "%Y-%m-%d %H:%M:%S", localtime(&unix_epoch));
printf("RTC: %lld %s\n", unix_epoch, rtc_time);
return icsneoc2_error_success;
}
void print_device_events(icsneoc2_device_t* device, const char* device_description) {
// Get device events
icsneoc2_event_t* events[1024] = {0};
uint32_t events_count = 1024;
icsneoc2_error_t res = icsneoc2_device_events_get(device, events, &events_count);
if (res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get device events", res);
return;
}
// Loop over each event and describe it.
for (uint32_t i = 0; i < events_count; i++) {
const char event_description[255] = {0};
uint32_t event_description_length = 255;
res = icsneoc2_event_description_get(events[i], event_description, &event_description_length);
if (res != icsneoc2_error_success) {
print_error_code("\tFailed to get event description", res);
continue;
}
printf("\t%s: Event %u: %s\n", device_description, i, event_description);
}
// Get global events
icsneoc2_event_t* global_events[1024] = {0};
uint32_t global_events_count = 1024;
res = icsneoc2_events_get(global_events, &global_events_count);
if (res != icsneoc2_error_success) {
(void)print_error_code("\tFailed to get global events", res);
return;
}
// Loop over each event and describe it.
for (uint32_t i = 0; i < global_events_count; i++) {
const char event_description[255] = {0};
uint32_t event_description_length = 255;
res = icsneoc2_event_description_get(global_events[i], event_description, &event_description_length);
if (res != icsneoc2_error_success) {
print_error_code("\tFailed to get global event description", res);
continue;
}
printf("\t%s: Global Event %u: %s\n", device_description, i, event_description);
}
printf("\t%s: Received %u events and %u global events\n", device_description, events_count, global_events_count);
}
int process_messages(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count) {
// Print the type and bus type of each message
uint32_t tx_count = 0;
for (uint32_t i = 0; i < messages_count; i++) {
icsneoc2_message_t* message = messages[i];
// Get the message type
icsneoc2_msg_type_t msg_type = 0;
icsneoc2_error_t res = icsneoc2_message_type_get(device, message, &msg_type);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message type", res);
}
// Get the message type name
char msg_type_name[128] = {0};
uint32_t msg_type_name_length = 128;
res = icsneoc2_message_type_name_get(msg_type, msg_type_name, &msg_type_name_length);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message type name", res);
}
// Check if the message is a bus message, ignore otherwise
if (msg_type != icsneoc2_msg_type_bus) {
printf("Ignoring message type: %u (%s)\n", msg_type, msg_type_name);
continue;
}
icsneoc2_msg_bus_type_t bus_type = 0;
res = icsneoc2_message_bus_type_get(device, message, &bus_type);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message bus type", res);
}
const char bus_name[128] = {0};
uint32_t bus_name_length = 128;
res = icsneoc2_bus_type_name_get(bus_type, bus_name, &bus_name_length);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message bus type name", res);
}
bool is_tx = false;
res = icsneoc2_message_is_transmit(device, message, &is_tx);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to get message is transmit", res);
}
if (is_tx) {
tx_count++;
continue;
}
printf("\t%d) Message type: %u bus type: %s (%u)\n", i, msg_type, bus_name, bus_type);
if (bus_type == icsneoc2_msg_bus_type_can) {
uint32_t arbid = 0;
int32_t dlc = 0;
icsneoc2_netid_t netid = 0;
bool is_remote = false;
bool is_canfd = false;
bool is_extended = false;
uint8_t data[64] = {0};
uint32_t data_length = 64;
const char netid_name[128] = {0};
uint32_t netid_name_length = 128;
uint32_t result = icsneoc2_message_netid_get(device, message, &netid);
result += icsneoc2_netid_name_get(netid, netid_name, &netid_name_length);
result += icsneoc2_message_can_arbid_get(device, message, &arbid);
result += icsneoc2_message_can_dlc_get(device, message, &dlc);
result += icsneoc2_message_can_is_remote(device, message, &is_remote);
result += icsneoc2_message_can_is_canfd(device, message, &is_canfd);
result += icsneoc2_message_can_is_extended(device, message, &is_extended);
result += icsneoc2_message_data_get(device, message, data, &data_length);
if (result != icsneoc2_error_success) {
printf("\tFailed get get CAN parameters (error: %u) for index %u\n", result, i);
continue;
}
printf("\t NetID: %s (0x%x)\tArbID: 0x%x\t DLC: %u\t Remote: %d\t CANFD: %d\t Extended: %d\t Data length: %u\n", netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length);
printf("\t Data: [");
for (uint32_t x = 0; x < data_length; x++) {
printf(" 0x%x", data[x]);
}
printf(" ]\n");
}
}
printf("\tReceived %u messages total, %u were TX messages\n", messages_count, tx_count);
return icsneoc2_error_success;
}
int transmit_can_messages(icsneoc2_device_t* device) {
uint64_t counter = 0;
const uint32_t msg_count = 100;
printf("\tTransmitting %d messages...\n", msg_count);
for (uint32_t i = 0; i < msg_count; i++) {
// Create the message
icsneoc2_message_t* message = NULL;
uint32_t message_count = 1;
icsneoc2_error_t res = icsneoc2_message_can_create(device, &message, message_count);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to create messages", res);
}
// Set the message attributes
res = icsneoc2_message_netid_set(device, message, icsneoc2_netid_hscan);
res += icsneoc2_message_can_arbid_set(device, message, 0x10);
res += icsneoc2_message_can_canfd_set(device, message, true);
res += icsneoc2_message_can_extended_set(device, message, true);
res += icsneoc2_message_can_baudrate_switch_set(device, message, true);
// Create the payload
uint8_t data[8] = {0};
data[0] = (uint8_t)(counter >> 56);
data[1] = (uint8_t)(counter >> 48);
data[2] = (uint8_t)(counter >> 40);
data[3] = (uint8_t)(counter >> 32);
data[4] = (uint8_t)(counter >> 24);
data[5] = (uint8_t)(counter >> 16);
data[6] = (uint8_t)(counter >> 8);
data[7] = (uint8_t)(counter >> 0);
res += icsneoc2_message_data_set(device, message, data, sizeof(data));
res += icsneoc2_message_can_dlc_set(device, message, -1);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to modify message", res);
}
res = icsneoc2_device_messages_transmit(device, &message, &message_count);
res += icsneoc2_message_can_free(device, message);
if (res != icsneoc2_error_success) {
return print_error_code("\tFailed to transmit messages", res);
}
counter++;
}
return icsneoc2_error_success;
}

View File

@ -259,8 +259,8 @@ void example4(const std::shared_ptr<icsneo::Device>& rada2b) {
auto handler = rada2b->addMessageCallback(std::make_shared<icsneo::MessageCallback>(
[] (std::shared_ptr<icsneo::Message> newMsg) {
if(newMsg->type == icsneo::Message::Type::Frame) {
const auto& frame = std::dynamic_pointer_cast<icsneo::Frame>(newMsg);
if(newMsg->type == icsneo::Message::Type::BusMessage) {
const auto& frame = std::dynamic_pointer_cast<icsneo::BusMessage>(newMsg);
if(frame && frame->network.getNetID() == icsneo::Network::NetID::I2C2) {
const auto& i2cMessage = std::dynamic_pointer_cast<icsneo::I2CMessage>(frame);

View File

@ -184,9 +184,9 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
void printMessage(const std::shared_ptr<icsneo::Message>& message) {
switch(message->type) {
case icsneo::Message::Type::Frame: {
case icsneo::Message::Type::BusMessage: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
@ -264,7 +264,7 @@ void printMessage(const std::shared_ptr<icsneo::Message>& message) {
break;
}
break;
} // end of icsneo::Message::Type::Frame
} // end of icsneo::Message::Type::BusMessage
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);

View File

@ -96,8 +96,8 @@ int main() {
std::cout << "OK" << std::endl << std::endl;
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) {
if(icsneo::Message::Type::Frame == message->type) {
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
if(icsneo::Message::Type::BusMessage == message->type) {
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
if(icsneo::Network::Type::LIN == frame->network.getType()) {
auto msg = std::static_pointer_cast<icsneo::LINMessage>(message);
std::cout << msg->network << " RX frame | ID: 0x" << std::hex << static_cast<int>(msg->ID) << " | ";

View File

@ -92,8 +92,8 @@ int main()
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message)
{
if(icsneo::Message::Type::Frame == message->type) {
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
if(icsneo::Message::Type::BusMessage == message->type) {
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
if(icsneo::Network::Type::MDIO == frame->network.getType()) {
auto msg = std::static_pointer_cast<icsneo::MDIOMessage>(message);
std::cout << msg->network << " " << ((msg->isTXMsg)? "TX" : "RX") << " frame\n";

View File

@ -169,9 +169,9 @@ int main() {
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([](std::shared_ptr<icsneo::Message> message) {
switch(message->type) {
case icsneo::Message::Type::Frame: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
case icsneo::Message::Type::BusMessage: {
// A message of type BusMessage is guaranteed to be a BusMessage, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::BusMessage>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
@ -202,7 +202,7 @@ int main() {
case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
std::cout << "\t\t" << ethMessage->network << " BusMessage - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
@ -249,7 +249,7 @@ int main() {
break;
}
break;
} // end of icsneo::Message::Type::Frame
} // end of icsneo::Message::Type::BusMessage
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorMessage>(message);

View File

@ -16,13 +16,13 @@ void onEvent(std::shared_ptr<icsneo::APIEvent> event) {
std::cout << event->describe() << std::endl;
}
std::vector<std::shared_ptr<icsneo::Frame>> constructRandomFrames(size_t frameCount, MessageType frameType) {
std::vector<std::shared_ptr<icsneo::BusMessage>> constructRandomFrames(size_t frameCount, MessageType frameType) {
static constexpr size_t ClassicCANSize = 8;
static constexpr size_t CANFDSize = 64;
static constexpr size_t ShortEthSize = 500;
static constexpr size_t LongEthSize = 1500;
std::vector<std::shared_ptr<icsneo::Frame>> frames;
std::vector<std::shared_ptr<icsneo::BusMessage>> frames;
std::random_device randDev;
std::mt19937 randEngine(randDev());
std::uniform_int_distribution randByteDist(0,255);
@ -166,10 +166,10 @@ int main(int argc, char* argv[]) {
uint64_t canFrameCount = 0;
uint64_t ethFrameCount = 0;
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
if(msg->type != icsneo::Message::Type::Frame) {
if(msg->type != icsneo::Message::Type::BusMessage) {
return;
}
const auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
const auto frame = std::static_pointer_cast<icsneo::BusMessage>(msg);
if(frame->network.getType() == icsneo::Network::Type::CAN) {
++canFrameCount;
} else if(frame->network.getType() == icsneo::Network::Type::Ethernet) {
@ -200,7 +200,7 @@ int main(int argc, char* argv[]) {
const uint8_t NumFrameTypes = 4;
const size_t FrameCountPerType = 2500;
std::vector<std::shared_ptr<icsneo::Frame>> frames;
std::vector<std::shared_ptr<icsneo::BusMessage>> frames;
for(uint8_t i = 0; i < NumFrameTypes; i++) {
std::cout << "info: transmitting " << FrameCountPerType << " random " << MessageTypeLabels[i] << " frames" << std::endl;
auto tempFrames = constructRandomFrames(FrameCountPerType, static_cast<MessageType>(i));
@ -216,10 +216,10 @@ int main(int argc, char* argv[]) {
size_t currentMessage = 0;
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
if(msg->type != icsneo::Message::Type::Frame) {
if(msg->type != icsneo::Message::Type::BusMessage) {
return;
}
auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
auto frame = std::static_pointer_cast<icsneo::BusMessage>(msg);
if(frames[currentMessage]->data == frame->data) {
currentMessage++;
}

View File

@ -0,0 +1,19 @@
libicsneoc2 simple Go example
====
This is a mirror of the icsneoc2 C simple example, written in Go.
Windows
====
- Install [msys64](https://www.msys2.org/) with gcc (`pacman -S mingw-w64-ucrt-x86_64-gcc`)
- Setup environment variables:
- add `C:\msys64\ucrt64\bin` to `PATH`
- Powershell: `$env:PATH += ";C:\msys64\ucrt64\bin"`
- `gcc --version` should return a version now
- enable cgo: `CGO_ENABLED = 1`
- Powershell: `$env:CGO_ENABLED=1`
- Set compiler to gcc
- Powershell: `$env:CC="gcc"`
- `icsneoc2.dll` should be in path (or inside this directory)
- `go run simple`

View File

@ -0,0 +1,3 @@
module simple
go 1.23.4

View File

@ -0,0 +1,354 @@
package main
// #cgo CFLAGS: -I../../../include
// #cgo LDFLAGS: -L../../../build -licsneoc2
// #include "icsneo/icsneoc2.h"
// #include "stdint.h"
import "C"
import (
"fmt"
"time"
"unsafe"
)
func main() {
// Find devices connected to host.
devices := [255]*C.icsneoc2_device_t{nil}
devicesCount := 255
print("Finding devices... ")
if res := C.icsneoc2_device_find_all(&devices[0], (*C.uint)(unsafe.Pointer(&devicesCount)), nil); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("OK, %d device(s) found\n", devicesCount)
// List off the devices
for _, device := range devices[:devicesCount] {
// Get description of the device
description := make([]byte, 255)
descriptionLength := 255
if res := C.icsneoc2_device_description_get(device, (*C.char)(unsafe.Pointer(&description[0])), (*C.uint)(unsafe.Pointer(&descriptionLength))); res != C.icsneoc2_error_success {
printError(res)
continue
}
fmt.Printf("%s @ Handle %p\n", description, device)
// Get/Set open options
options := C.icsneoc2_open_options_none
if res := C.icsneoc2_device_open_options_get(device, (*C.icsneoc2_open_options_t)(unsafe.Pointer(&options))); res != C.icsneoc2_error_success {
printError(res)
continue
}
options &= ^C.icsneoc2_open_options_sync_rtc
options &= ^C.icsneoc2_open_options_go_online
fmt.Printf("\tDevice open options: 0x%X\n", options)
if res := C.icsneoc2_device_open_options_set(device, (C.icsneoc2_open_options_t)(options)); res != C.icsneoc2_error_success {
printError(res)
continue
}
// Open the device
fmt.Printf("\tOpening device: %s...\n", description)
if res := C.icsneoc2_device_open(device); res != C.icsneoc2_error_success {
printError(res)
continue
}
defer func() {
if !printDeviceEvents(device, string(description)) {
println("\tFailed to print events...")
}
fmt.Printf("\tClosing device: %s...\n", description)
if res := C.icsneoc2_device_close(device); res != C.icsneoc2_error_success {
printError(res)
return
}
}()
// Get timestamp resolution of the device
fmt.Printf("\tGetting timestamp resolution... ")
var timestampResolution C.uint = 0
if res := C.icsneoc2_device_timestamp_resolution_get(device, &timestampResolution); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("%dns\n", timestampResolution)
// Get baudrates for HSCAN
fmt.Printf("\tGetting HSCAN Baudrate... ")
var baudrate uint64 = 0
if res := C.icsneoc2_device_baudrate_get(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (*C.uint64_t)(unsafe.Pointer(&baudrate))); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("%dmbit/s\n", baudrate)
// Get FD baudrates for HSCAN
fmt.Printf("\tGetting FD HSCAN Baudrate... ")
var fdBaudrate uint64 = 0
if res := C.icsneoc2_device_canfd_baudrate_get(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (*C.uint64_t)(unsafe.Pointer(&fdBaudrate))); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("%dmbit/s\n", fdBaudrate)
// Set baudrates for HSCAN
// saveToDevice: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
var saveToDevice C.bool = false
fmt.Printf("\tSetting HSCAN Baudrate... ")
if res := C.icsneoc2_device_baudrate_set(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (C.uint64_t)(baudrate), saveToDevice); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("OK\n")
// Set FD baudrates for HSCAN
fmt.Printf("\tSetting FD HSCAN Baudrate... ")
if res := C.icsneoc2_device_canfd_baudrate_set(device, (C.icsneoc2_netid_t)(C.icsneoc2_netid_hscan), (C.uint64_t)(fdBaudrate), saveToDevice); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("OK\n")
// Get RTC
fmt.Printf("\tGetting RTC... ")
var unix_epoch C.int64_t = 0
if res := C.icsneoc2_device_rtc_get(device, (*C.int64_t)(unsafe.Pointer(&unix_epoch))); res != C.icsneoc2_error_success {
printError(res)
return
}
currentRTC := time.Unix(int64(unix_epoch), 0)
fmt.Printf("%d %s\n", currentRTC.Unix(), currentRTC)
// Set RTC
fmt.Printf("\tSetting RTC... ")
unix_epoch = (C.int64_t)(time.Now().Unix())
if res := C.icsneoc2_device_rtc_set(device, unix_epoch); res != C.icsneoc2_error_success {
printError(res)
return
}
fmt.Printf("OK\n")
// Get RTC
fmt.Printf("\tGetting RTC... ")
if res := C.icsneoc2_device_rtc_get(device, (*C.int64_t)(unsafe.Pointer(&unix_epoch))); res != C.icsneoc2_error_success {
printError(res)
return
}
currentRTC = time.Unix(int64(unix_epoch), 0)
fmt.Printf("%d %s\n", currentRTC.Unix(), currentRTC)
// Go online, start acking traffic
fmt.Printf("\tGoing online... ")
if res := C.icsneoc2_device_go_online(device, true); res != C.icsneoc2_error_success {
printError(res)
return
}
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
var isOnline C.bool = false
if res := C.icsneoc2_device_is_online(device, &isOnline); res != C.icsneoc2_error_success {
printError(res)
return
}
if isOnline {
println("Online")
} else {
println("Offline")
}
// Transmit CAN messages
if !transmitCANMessages(device) {
return
}
// Wait for the bus to collect some messages, requires an active bus to get messages
println("\tWaiting 1 second for messages...")
time.Sleep(1 * time.Second)
// Get the messages
messages := [20000]*C.icsneoc2_message_t{nil}
var messagesCount C.uint32_t = 20000
if res := C.icsneoc2_device_messages_get(device, &messages[0], &messagesCount, 3000); res != C.icsneoc2_error_success {
printError(res)
return
}
// Process the messages
if !processMessages(device, messages[0:messagesCount]) {
return
}
}
}
func printError(err C.icsneoc2_error_t) C.icsneoc2_error_t {
buffer := make([]byte, 255)
bufferLength := 255
res := C.icsneoc2_error_code_get(err, (*C.char)(unsafe.Pointer(&buffer[0])), (*C.uint)(unsafe.Pointer(&bufferLength)))
if res != C.icsneoc2_error_success {
println("\ticsneoc2_get_error_code failed, original error:", err)
return res
}
println("\tError:", string(buffer[:bufferLength]))
return res
}
func printDeviceEvents(device *C.icsneoc2_device_t, deviceDescription string) bool {
// Get device events
events := [1024]*C.icsneoc2_event_t{nil}
var eventsCount C.uint32_t = 1024
if res := C.icsneoc2_device_events_get(device, &events[0], &eventsCount); res != C.icsneoc2_error_success {
printError(res)
return false
}
for i, event := range events[:eventsCount] {
eventDescription := make([]byte, 255)
var eventDescriptionLength C.uint32_t = 255
if res := C.icsneoc2_event_description_get(event, (*C.char)(unsafe.Pointer(&eventDescription[0])), &eventDescriptionLength); res != C.icsneoc2_error_success {
printError(res)
continue
}
fmt.Printf("\t%s: Event %d: %s\n", deviceDescription, i, eventDescription)
}
// Get global events
globalEvents := [1024]*C.icsneoc2_event_t{nil}
var globalEventsCount C.uint32_t = 1024
if res := C.icsneoc2_events_get(&globalEvents[0], &globalEventsCount); res != C.icsneoc2_error_success {
printError(res)
return false
}
for i, event := range globalEvents[:globalEventsCount] {
globalEventsDescription := make([]byte, 255)
var globalEventsDescriptionLength C.uint32_t = 255
if res := C.icsneoc2_event_description_get(event, (*C.char)(unsafe.Pointer(&globalEventsDescription[0])), &globalEventsDescriptionLength); res != C.icsneoc2_error_success {
printError(res)
continue
}
fmt.Printf("\t%s: Global Event %d: %s\n", deviceDescription, i, globalEventsDescription)
}
fmt.Printf("\t%s: Received %d events and %d global events\n", deviceDescription, eventsCount, globalEventsCount)
return true
}
func transmitCANMessages(device *C.icsneoc2_device_t) bool {
var counter uint32 = 0
const msgCount int = 100
fmt.Printf("\tTransmitting %d messages...\n", msgCount)
for range msgCount {
// Create the message
var message *C.icsneoc2_message_t = nil
if res := C.icsneoc2_message_can_create(device, &message, 1); res != C.icsneoc2_error_success {
printError(res)
return false
}
defer func() {
if res := C.icsneoc2_message_can_free(device, message); res != C.icsneoc2_error_success {
printError(res)
}
}()
// Set the message attributes
res := C.icsneoc2_message_netid_set(device, message, C.icsneoc2_netid_hscan)
res += C.icsneoc2_message_can_arbid_set(device, message, 0x10)
res += C.icsneoc2_message_can_canfd_set(device, message, true)
res += C.icsneoc2_message_can_extended_set(device, message, true)
res += C.icsneoc2_message_can_baudrate_switch_set(device, message, true)
// Create the payload
data := [...]C.uint8_t{
(C.uint8_t)(counter >> 56),
(C.uint8_t)(counter >> 48),
(C.uint8_t)(counter >> 40),
(C.uint8_t)(counter >> 32),
(C.uint8_t)(counter >> 24),
(C.uint8_t)(counter >> 16),
(C.uint8_t)(counter >> 8),
(C.uint8_t)(counter >> 0),
}
res += C.icsneoc2_message_data_set(device, message, &data[0], (C.uint32_t)(len(data)))
res += C.icsneoc2_message_can_dlc_set(device, message, -1)
if res != C.icsneoc2_error_success {
fmt.Printf("\tFailed to modify message: %d\n", res)
return false
}
var messageCount C.uint32_t = 1
if res := C.icsneoc2_device_messages_transmit(device, &message, &messageCount); res != C.icsneoc2_error_success {
printError(res)
return false
}
counter += 1
}
return true
}
func processMessages(device *C.icsneoc2_device_t, messages []*C.icsneoc2_message_t) bool {
txCount := 0
for i, message := range messages {
// Get the message type
var msgType C.icsneoc2_msg_type_t = 0
if res := C.icsneoc2_message_type_get(device, message, &msgType); res != C.icsneoc2_error_success {
printError(res)
return false
}
// Get the message type name
msgTypeName := make([]byte, 128)
var msgTypeNameLength C.uint32_t = 128
if res := C.icsneoc2_message_type_name_get(msgType, (*C.char)(unsafe.Pointer(&msgTypeName[0])), &msgTypeNameLength); res != C.icsneoc2_error_success {
printError(res)
return false
}
// Check if the message is a bus message, ignore otherwise
if msgType != C.icsneoc2_msg_type_bus {
fmt.Print("\tIgnoring message type: %d (%s)\n", msgType, msgTypeName)
continue
}
// Get the message bus type
var msgBusType C.icsneoc2_msg_bus_type_t = 0
if res := C.icsneoc2_message_bus_type_get(device, message, &msgBusType); res != C.icsneoc2_error_success {
printError(res)
return false
}
// Get the bus message type name
msgBusTypeName := make([]byte, 128)
var msgBusTypeNameLength C.uint32_t = 128
if res := C.icsneoc2_bus_type_name_get(msgBusType, (*C.char)(unsafe.Pointer(&msgBusTypeName[0])), &msgBusTypeNameLength); res != C.icsneoc2_error_success {
printError(res)
return false
}
// Check if the message is a transmit message
var isTransmit C.bool = false
if res := C.icsneoc2_message_is_transmit(device, message, &isTransmit); res != C.icsneoc2_error_success {
printError(res)
return false
}
if isTransmit {
txCount += 1
continue
}
fmt.Printf("\t%d) Message type: %d bus type: %s (%d)\n", i, msgType, msgBusTypeName, msgBusType)
if msgBusType == C.icsneoc2_msg_bus_type_can {
var arbid C.uint32_t = 0
var dlc C.int32_t = 0
var netid C.icsneoc2_netid_t = 0
var isRemote C.bool = false
var isCanfd C.bool = false
var isExtended C.bool = false
data := make([]byte, 64)
var dataLength C.uint32_t = 64
netidName := make([]byte, 128)
var netidNameLength C.uint32_t = 128
var res C.icsneoc2_error_t = C.icsneoc2_error_success
res = C.icsneoc2_message_netid_get(device, message, &netid)
res += C.icsneoc2_netid_name_get(netid, (*C.char)(unsafe.Pointer(&netidName)), &netidNameLength)
res += C.icsneoc2_message_can_arbid_get(device, message, &arbid)
res += C.icsneoc2_message_can_dlc_get(device, message, &dlc)
res += C.icsneoc2_message_can_is_remote(device, message, &isRemote)
res += C.icsneoc2_message_can_is_canfd(device, message, &isCanfd)
res += C.icsneoc2_message_can_is_extended(device, message, &isExtended)
res += C.icsneoc2_message_data_get(device, message, (*C.uint8_t)(unsafe.Pointer(&data[0])), &dataLength)
// We really should check the error message for all of these since we can't tell the exact error if something
// bad happens but for an example this should be okay.
if res != C.icsneoc2_error_success {
fmt.Printf("\tFailed to get CAN parameters (error: %d) for index %d\n", res, i)
continue
}
// Finally lets print the RX message
fmt.Printf("\t NetID: %s (0x%X)\tArbID: 0x%X\t DLC: %d\t Remote: %t\t CANFD: %t\t Extended: %t\t Data length: %d\n", netidName, netid, arbid, dlc, isRemote, isCanfd, isExtended, dataLength)
fmt.Printf("\t Data: [")
for _, d := range data[:dataLength] {
fmt.Printf(" 0x%X", d)
}
println(" ]")
continue
} else {
fmt.Printf("\tIgnoring bus message type: %d (%s)\n", msgBusType, msgBusTypeName)
continue
}
}
fmt.Printf("\tReceived %d messages total, %d were TX messages\n", len(messages), txCount)
return true
}

22
examples/zig/simple/.gitignore vendored 100644
View File

@ -0,0 +1,22 @@
# This file is for zig-specific build artifacts.
# If you have OS-specific or editor-specific files to ignore,
# such as *.swp or .DS_Store, put those in your global
# ~/.gitignore and put this in your ~/.gitconfig:
#
# [core]
# excludesfile = ~/.gitignore
#
# Cheers!
# -andrewrk
.zig-cache/
zig-out/
/release/
/debug/
/build/
/build-*/
/docgen_tmp/
# Although this was renamed to .zig-cache, let's leave it here for a few
# releases to make it less annoying to work with multiple branches.
zig-cache/

View File

@ -0,0 +1,72 @@
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{ .default_target = .{ .abi = .msvc } });
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "simple",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
exe.linkLibC();
// Add support for icsneoc2
exe.addIncludePath(b.path("../../../include"));
exe.addLibraryPath(b.path("../../../build"));
exe.linkSystemLibrary("icsneoc2");
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(exe);
// This *creates* a Run step in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const exe_unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_exe_unit_tests.step);
}

View File

@ -0,0 +1,72 @@
.{
// This is the default name used by packages depending on this one. For
// example, when a user runs `zig fetch --save <url>`, this field is used
// as the key in the `dependencies` table. Although the user can choose a
// different name, most users will stick with this provided value.
//
// It is redundant to include "zig" in this name because it is already
// within the Zig package namespace.
.name = "simple",
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.0",
// This field is optional.
// This is currently advisory only; Zig does not yet do anything
// with this value.
//.minimum_zig_version = "0.11.0",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
//.example = .{
// // When updating this field to a new URL, be sure to delete the corresponding
// // `hash`, otherwise you are communicating that you expect to find the old hash at
// // the new URL.
// .url = "https://example.com/foo.tar.gz",
//
// // This is computed from the file contents of the directory of files that is
// // obtained after fetching `url` and applying the inclusion rules given by
// // `paths`.
// //
// // This field is the source of truth; packages do not come from a `url`; they
// // come from a `hash`. `url` is just one of many possible mirrors for how to
// // obtain a package matching this `hash`.
// //
// // Uses the [multihash](https://multiformats.io/multihash/) format.
// .hash = "...",
//
// // When this is provided, the package is found in a directory relative to the
// // build root. In this case the package's hash is irrelevant and therefore not
// // computed. This field and `url` are mutually exclusive.
// .path = "foo",
//
// // When this is set to `true`, a package is declared to be lazily
// // fetched. This makes the dependency only get fetched if it is
// // actually used.
// .lazy = false,
//},
},
// Specifies the set of files and directories that are included in this package.
// Only files and directories listed here are included in the `hash` that
// is computed for this package. Only files listed here will remain on disk
// when using the zig package manager. As a rule of thumb, one should list
// files required for compilation plus any license(s).
// Paths are relative to the build root. Use the empty string (`""`) to refer to
// the build root itself.
// A directory listed here means that all files within, recursively, are included.
.paths = .{
"build.zig",
"build.zig.zon",
"src",
// For example...
//"LICENSE",
//"README.md",
},
}

View File

@ -0,0 +1,421 @@
const std = @import("std");
const print = std.debug.print;
const ics = @cImport({
@cInclude("icsneo/icsneoc2.h");
@cInclude("icsneo/icsneoc2types.h");
});
const c = @cImport({
@cInclude("time.h");
});
pub fn main() !void {
// Find devices connected to host.
const MAX_DEVICE_COUNT: u32 = 255;
var device_buffer: [MAX_DEVICE_COUNT]?*ics.icsneoc2_device_t = undefined;
var devices_count: u32 = MAX_DEVICE_COUNT;
print("Finding devices... ", .{});
if (!check_error(
ics.icsneoc2_device_find_all(&device_buffer, &devices_count, null),
"Failed to find device",
)) {
return;
}
print("OK, {d} device{s} found\n", .{ devices_count, if (devices_count == 1) "" else "s" });
// Lets just take a slice of the entire device buffer
const devices = device_buffer[0..devices_count];
// List off the devices
for (devices) |device| {
// Get description of the device
var description: [255]u8 = [_:0]u8{0} ** 255;
var description_length: u32 = 255;
if (!check_error(
ics.icsneoc2_device_description_get(device, &description, &description_length),
"\tFailed to get device description",
)) {
return;
}
print("{s}. {*}\n", .{ description, device.? });
// Get/Set open options
var options: ics.icsneoc2_open_options_t = ics.icsneoc2_open_options_none;
if (!check_error(
ics.icsneoc2_device_open_options_get(device, &options),
"\tFailed to get device open options",
)) {
return;
}
// Disable Syncing RTC and going online
options &= ~@as(ics.icsneoc2_open_options_t, ics.icsneoc2_open_options_sync_rtc);
options &= ~@as(ics.icsneoc2_open_options_t, ics.icsneoc2_open_options_go_online);
print("\tDevice open options: 0x{X}\n", .{options});
if (!check_error(
ics.icsneoc2_device_open_options_set(device, options),
"\tFailed to set device open options",
)) {
return;
}
// Open the device
print("\tOpening device: {s}...\n", .{description});
if (!check_error(
ics.icsneoc2_device_open(device),
"\tFailed to open device",
)) {
return;
}
defer {
// Finally, close the device.
if (!print_device_events(device)) {
print("\tFailed to print events...\n", .{});
}
print("\tClosing device: {s}... ", .{description});
if (check_error(
ics.icsneoc2_device_close(device),
"\tFailed to close device",
)) {
print("OK\n", .{});
}
}
// Get timestamp resolution of the device
print("\tGetting timestamp resolution... ", .{});
var timestamp_resolution: u32 = 0;
if (!check_error(
ics.icsneoc2_device_timestamp_resolution_get(device, &timestamp_resolution),
"\tFailed to get timestamp resolution",
)) {
return;
}
print("{d}ns\n", .{timestamp_resolution});
// Get baudrates for HSCAN
print("\tGetting HSCAN baudrate... ", .{});
var baudrate: u64 = 0;
if (!check_error(
ics.icsneoc2_device_baudrate_get(device, ics.icsneoc2_netid_hscan, &baudrate),
"\tFailed to get baudrate",
)) {
return;
}
print("{d}mbit/s\n", .{baudrate});
// Get FDbaudrates for HSCAN
print("\tGetting FD HSCAN baudrate... ", .{});
var fd_baudrate: u64 = 0;
if (!check_error(
ics.icsneoc2_device_canfd_baudrate_get(device, ics.icsneoc2_netid_hscan, &fd_baudrate),
"\tFailed to get FD baudrate",
)) {
return;
}
print("{d}mbit/s\n", .{fd_baudrate});
// Set baudrates for HSCAN
// save_to_device: If this is set to true, the baudrate will be saved on the device
// and will persist through a power cycle
print("\tSetting HSCAN Baudrate... ", .{});
const save_to_device: bool = false;
if (!check_error(
ics.icsneoc2_device_baudrate_set(device, ics.icsneoc2_netid_hscan, baudrate, save_to_device),
"\tFailed to set baudrate",
)) {
return;
}
print("OK\n", .{});
// Set FDbaudrates for HSCAN
print("\tSetting FD HSCAN Baudrate... ", .{});
if (!check_error(
ics.icsneoc2_device_canfd_baudrate_set(device, ics.icsneoc2_netid_hscan, baudrate, save_to_device),
"\tFailed to set FD baudrate",
)) {
return;
}
print("OK\n", .{});
// Get RTC
print("\tGetting RTC... ", .{});
var unix_epoch: c.time_t = 0;
if (!check_error(
ics.icsneoc2_device_rtc_get(device, &unix_epoch),
"\tFailed to get RTC",
)) {
return;
}
print_rtc(unix_epoch);
// Set RTC
print("\tSetting RTC to current time... ", .{});
const current_time: i64 = c.time(0);
if (!check_error(
ics.icsneoc2_device_rtc_set(device, current_time),
"\tFailed to set RTC",
)) {
return;
}
print("OK\n", .{});
// Get RTC
print("\tGetting RTC... ", .{});
if (!check_error(
ics.icsneoc2_device_rtc_get(device, &unix_epoch),
"\tFailed to get RTC",
)) {
return;
}
print_rtc(unix_epoch);
// Go online, start acking traffic
print("\tGoing online... ", .{});
if (!check_error(
ics.icsneoc2_device_go_online(device, true),
"\tFailed to go online",
)) {
return;
}
// Redundant check to show how to check if the device is online, if the previous
// icsneoc2_device_go_online call was successful we can assume we are online already
var is_online: bool = false;
if (!check_error(
ics.icsneoc2_device_is_online(device, &is_online),
"\tFailed to check if online",
)) {
return;
}
print("{s}\n", .{if (is_online) "Online" else "Offline"});
// Transmit CAN messages
if (!transmit_can_messages(device)) {
return;
}
// Wait for the bus to collect some messages, requires an active bus to get messages
print("\tWaiting 1 second for messages...\n", .{});
std.time.sleep(std.time.ns_per_s);
// Get the messages
var messages: [20000]?*ics.icsneoc2_message_t = [_]?*ics.icsneoc2_message_t{null} ** 20000;
var messages_count: u32 = 20000;
const res = ics.icsneoc2_device_messages_get(device, &messages, &messages_count, 3000);
if (!check_error(
res,
"\tFailed to get messages on device",
)) {
return;
}
// Process the messages
if (!process_messages(device, messages[0..messages_count])) {
return;
}
}
}
pub fn check_error(error_code: ics.icsneoc2_error_t, error_msg: []const u8) bool {
if (error_code == ics.icsneoc2_error_success) {
return true;
}
var error_str: [256]u8 = [_:0]u8{0} ** 256;
var error_length: u32 = 256;
const res: ics.icsneoc2_error_t = ics.icsneoc2_error_code_get(
error_code,
&error_str,
&error_length,
);
if (res != ics.icsneoc2_error_success) {
print(
"{s}: Failed to get string for error code {d} with error code {d}\n",
.{ error_msg, error_code, res },
);
return false;
}
print(
"{s}: \"{s}\" ({d})\n",
.{ error_msg, error_str, error_code },
);
return error_code == ics.icsneoc2_error_success;
}
pub fn print_rtc(unix_epoch: c.time_t) void {
var rtc_time: [32]u8 = [_:0]u8{0} ** 32;
_ = c.strftime(&rtc_time, rtc_time.len, "%Y-%m-%d %H:%M:%S", c.localtime(&unix_epoch));
print("{d} {s}\n", .{ unix_epoch, rtc_time });
}
pub fn transmit_can_messages(device: ?*ics.icsneoc2_device_t) bool {
const msg_count: usize = 100;
print("\tTransmitting {} messages...\n", .{msg_count});
for (0..msg_count) |counter| {
// Create the message
var message: ?*ics.icsneoc2_message_t = null;
var message_count: u32 = 1;
if (!check_error(
ics.icsneoc2_message_can_create(device, &message, message_count),
"\tFailed to create CAN message",
)) {
return false;
}
defer {
_ = check_error(
ics.icsneoc2_message_can_free(device, message),
"\tFailed to free CAN message",
);
}
// Set the message attributes
var res: ics.icsneoc2_error_t = ics.icsneoc2_message_netid_set(device, message, ics.icsneoc2_netid_hscan);
res += ics.icsneoc2_message_can_arbid_set(device, message, 0x10);
res += ics.icsneoc2_message_can_canfd_set(device, message, true);
res += ics.icsneoc2_message_can_extended_set(device, message, true);
res += ics.icsneoc2_message_can_baudrate_switch_set(device, message, true);
// Create the payload
var data: [8]u8 = .{
@intCast(counter >> 56),
@intCast(counter >> 48),
@intCast(counter >> 40),
@intCast(counter >> 32),
@intCast(counter >> 24),
@intCast(counter >> 16),
@intCast(counter >> 8),
@intCast(counter >> 0),
};
res += ics.icsneoc2_message_data_set(device, message, &data, data.len);
res += ics.icsneoc2_message_can_dlc_set(device, message, -1);
if (!check_error(res, "\tFailed to set CAN Message attributes!")) {
return false;
}
if (!check_error(
ics.icsneoc2_device_messages_transmit(device, &message, &message_count),
"\tFailed to transmit message",
)) {
return false;
}
}
return true;
}
pub fn process_messages(device: ?*ics.icsneoc2_device_t, messages: []const ?*ics.icsneoc2_message_t) bool {
var tx_count: usize = 0;
for (messages, 0..) |message, i| {
// Get the message type
var msg_type: ics.icsneoc2_msg_type_t = 0;
if (!check_error(
ics.icsneoc2_message_type_get(device, message.?, &msg_type),
"\tFailed to get message type",
)) {
return false;
}
// Get the message type name
var msg_type_name: [128]u8 = [_:0]u8{0} ** 128;
var msg_type_name_length: u32 = 128;
if (!check_error(
ics.icsneoc2_message_type_name_get(msg_type, &msg_type_name, &msg_type_name_length),
"\tFailed to get message type name",
)) {
return false;
}
// Check if the message is a bus message, ignore otherwise
if (msg_type != ics.icsneoc2_msg_type_bus) {
print("\tIgnoring message type: {d} ({s})\n", .{ msg_type, msg_type_name });
continue;
}
// Get the message bus type
var msg_bus_type: ics.icsneoc2_msg_bus_type_t = 0;
if (!check_error(
ics.icsneoc2_message_bus_type_get(device, message, &msg_bus_type),
"\tFailed to get message bus type",
)) {
return false;
}
// Get the message type name
var msg_bus_type_name: [128]u8 = [_:0]u8{0} ** 128;
var msg_bus_type_name_length: u32 = 128;
if (!check_error(
ics.icsneoc2_bus_type_name_get(msg_bus_type, &msg_bus_type_name, &msg_bus_type_name_length),
"\tFailed to get message bus type name",
)) {
return false;
}
// Check if message is a transmit message
var is_tx: bool = false;
if (!check_error(
ics.icsneoc2_message_is_transmit(device, message, &is_tx),
"\tFailed to get message is transmit",
)) {
return false;
}
if (is_tx) {
tx_count += 1;
continue;
}
print("\t{d} Message type: {d} bus type: {s} ({d})\n", .{ i, msg_type, msg_bus_type_name, msg_bus_type });
// Check if the message is a CAN message, ignore otherwise
if (msg_bus_type == ics.icsneoc2_msg_bus_type_can) {
var arbid: u32 = 0;
var dlc: i32 = 0;
var netid: ics.icsneoc2_netid_t = 0;
var is_remote: bool = false;
var is_canfd: bool = false;
var is_extended: bool = false;
var data: [64]u8 = [_]u8{0} ** 64;
var data_length: u32 = 64;
var netid_name: [128]u8 = [_:0]u8{0} ** 128;
var netid_name_length: u32 = 128;
var res: ics.icsneoc2_error_t = ics.icsneoc2_error_success;
res = ics.icsneoc2_message_netid_get(device, message, &netid);
res += ics.icsneoc2_netid_name_get(netid, &netid_name, &netid_name_length);
res += ics.icsneoc2_message_can_arbid_get(device, message, &arbid);
res += ics.icsneoc2_message_can_dlc_get(device, message, &dlc);
res += ics.icsneoc2_message_can_is_remote(device, message, &is_remote);
res += ics.icsneoc2_message_can_is_canfd(device, message, &is_canfd);
res += ics.icsneoc2_message_can_is_extended(device, message, &is_extended);
res += ics.icsneoc2_message_data_get(device, message, &data, &data_length);
// We really should check the error message for all of these since we can't tell the exact error if something
// bad happens but for an example this should be okay.
if (res != ics.icsneoc2_error_success) {
print("\tFailed to get CAN parameters (error: {d}) for index {d}\n", .{ res, i });
continue;
}
// Finally lets print the RX message
print("\t NetID: {s} (0x{X})\tArbID: 0x{X}\t DLC: {d}\t Remote: {}\t CANFD: {}\t Extended: {}\t Data length: {d}\n", .{ netid_name, netid, arbid, dlc, is_remote, is_canfd, is_extended, data_length });
print("\t Data: {any}\n", .{data[0..data_length]});
} else {
print("\tIgnoring bus message type: {d} ({s})\n", .{ msg_bus_type, msg_bus_type_name });
continue;
}
}
print("\tReceived {d} messages total, {d} were TX messages\n", .{ messages.len, tx_count });
return true;
}
pub fn print_device_events(device: ?*ics.icsneoc2_device_t) bool {
// Get device events
var events: [1024]?*ics.icsneoc2_event_t = [_]?*ics.icsneoc2_event_t{null} ** 1024;
var events_count: u32 = 1024;
if (!check_error(
ics.icsneoc2_device_events_get(device, &events, &events_count),
"\tFailed to get device events",
)) {
return false;
}
for (events[0..events_count], 0..) |event, i| {
var event_description: [256]u8 = [_:0]u8{0} ** 256;
var event_description_length: u32 = 256;
if (!check_error(
ics.icsneoc2_event_description_get(event, &event_description, &event_description_length),
"\tFailed to get event description",
)) {
continue;
}
print("\tEvent {d}: {s}\n", .{ i, event_description });
}
// Get global events
var global_events: [1024]?*ics.icsneoc2_event_t = [_]?*ics.icsneoc2_event_t{null} ** 1024;
var global_events_count: u32 = 1024;
if (!check_error(
ics.icsneoc2_events_get(&global_events, &global_events_count),
"\tFailed to get device global events",
)) {
return false;
}
for (global_events[0..global_events_count], 0..) |event, i| {
var event_description: [256]u8 = [_:0]u8{0} ** 256;
var event_description_length: u32 = 256;
if (!check_error(
ics.icsneoc2_event_description_get(event, &event_description, &event_description_length),
"\tFailed to get event description",
)) {
continue;
}
print("\tGlobal event {d}: {s}\n", .{ i, event_description });
}
print("\tReceived {d} events and {d} global events\n", .{ events_count, global_events_count });
return true;
}

View File

@ -20,8 +20,10 @@ enum class PCMType : uint8_t {
using ChannelMap = std::unordered_map<uint8_t, uint8_t>;
class A2BMessage : public Frame {
class A2BMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::A2B; }
static constexpr size_t maxAudioBufferSize = 2048;
enum class TDMMode : uint8_t {

View File

@ -64,9 +64,9 @@ enum class AppErrorType : uint16_t {
AppNoError = 255
};
class AppErrorMessage : public RawMessage {
class AppErrorMessage : public InternalMessage {
public:
AppErrorMessage() : RawMessage(Message::Type::AppError, Network::NetID::RED_App_Error) {}
AppErrorMessage() : InternalMessage(Message::Type::AppError, Network::NetID::RED_App_Error) {}
uint16_t errorType;
Network::NetID errorNetID;
uint32_t timestamp10us;

View File

@ -7,8 +7,10 @@
namespace icsneo {
class CANMessage : public Frame {
class CANMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::CAN; }
uint32_t arbid;
uint8_t dlcOnWire;
bool isRemote = false; // Not allowed if CAN FD

View File

@ -7,9 +7,9 @@
namespace icsneo {
class DiskDataMessage : public RawMessage {
class DiskDataMessage : public InternalMessage {
public:
DiskDataMessage(std::vector<uint8_t>&& d) : RawMessage(Network::NetID::DiskData) {
DiskDataMessage(std::vector<uint8_t>&& d) : InternalMessage(Network::NetID::DiskData) {
data = std::move(d);
}
};

View File

@ -31,8 +31,10 @@ struct MACAddress {
}
};
class EthernetMessage : public Frame {
class EthernetMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::Ethernet; }
bool preemptionEnabled = false;
uint8_t preemptionFlags = 0;
std::optional<uint32_t> fcs;

View File

@ -9,7 +9,7 @@
namespace icsneo {
class ExtendedDataMessage : public Frame {
class ExtendedDataMessage : public InternalMessage {
public:
#pragma pack(push, 2)
struct ExtendedDataHeader {

View File

@ -13,8 +13,8 @@ namespace icsneo {
class CANMessageFilter : public MessageFilter {
public:
CANMessageFilter() : MessageFilter(Network::Type::CAN), arbid(INVALID_ARBID) { messageType = Message::Type::Frame; }
CANMessageFilter(uint32_t arbid) : MessageFilter(Network::Type::CAN), arbid(arbid) { messageType = Message::Type::Frame; }
CANMessageFilter() : MessageFilter(Network::Type::CAN), arbid(INVALID_ARBID) { messageType = Message::Type::BusMessage; }
CANMessageFilter(uint32_t arbid) : MessageFilter(Network::Type::CAN), arbid(arbid) { messageType = Message::Type::BusMessage; }
bool match(const std::shared_ptr<Message>& message) const {
if(!MessageFilter::match(message))

View File

@ -27,9 +27,9 @@ public:
if(!matchMessageType(message->type))
return false;
if(message->type == Message::Type::Frame || message->type == Message::Type::Main51 ||
message->type == Message::Type::RawMessage || message->type == Message::Type::ReadSettings) {
const auto frame = std::static_pointer_cast<RawMessage>(message);
if(message->type == Message::Type::BusMessage || message->type == Message::Type::Main51 ||
message->type == Message::Type::InternalMessage || message->type == Message::Type::ReadSettings) {
const auto frame = std::static_pointer_cast<InternalMessage>(message);
if(!matchNetworkType(frame->network.getType()))
return false;
if(!matchNetID(frame->network.getNetID()))

View File

@ -7,9 +7,9 @@
namespace icsneo {
class FlashMemoryMessage : public RawMessage {
class FlashMemoryMessage : public InternalMessage {
public:
FlashMemoryMessage() : RawMessage(Message::Type::RawMessage, Network::NetID::RED_INT_MEMORYREAD) {}
FlashMemoryMessage() : InternalMessage(Message::Type::InternalMessage, Network::NetID::RED_INT_MEMORYREAD) {}
uint16_t startAddress = 0;
};

View File

@ -10,8 +10,10 @@
namespace icsneo {
class FlexRayMessage : public Frame {
class FlexRayMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::FlexRay; }
uint16_t slotid = 0;
double tsslen = 0;
double framelen = 0;

View File

@ -8,8 +8,10 @@
namespace icsneo {
class I2CMessage : public Frame {
class I2CMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::I2C; }
enum class DeviceMode : uint8_t {
Target = 0,
Controller = 1

View File

@ -8,8 +8,10 @@
namespace icsneo {
class ISO9141Message : public Frame {
class ISO9141Message : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::ISO9141; }
std::array<uint8_t, 3> header;
bool isInit = false;
bool isBreak = false;

View File

@ -34,8 +34,10 @@ struct LINStatusFlags {
bool BreakOnly = false;
};
class LINMessage : public Frame {
class LINMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::LIN; }
enum class Type : uint8_t {
NOT_SET = 0,
LIN_COMMANDER_MSG,

View File

@ -8,9 +8,9 @@
#include "icsneo/communication/livedata.h"
namespace icsneo {
class LiveDataMessage : public RawMessage {
class LiveDataMessage : public InternalMessage {
public:
LiveDataMessage() : RawMessage(Message::Type::LiveData, Network::NetID::ExtendedCommand) {}
LiveDataMessage() : InternalMessage(Message::Type::LiveData, Network::NetID::ExtendedCommand) {}
LiveDataHandle handle;
LiveDataCommand cmd;
};

View File

@ -8,9 +8,9 @@
namespace icsneo {
class Main51Message : public RawMessage {
class Main51Message : public InternalMessage {
public:
Main51Message() : RawMessage(Message::Type::Main51, Network::NetID::Main51) {}
Main51Message() : InternalMessage(Message::Type::Main51, Network::NetID::Main51) {}
Command command = Command(0);
bool forceShortFormat = false; // Necessary for EnableNetworkCom and EnableNetworkComEx
};

View File

@ -7,8 +7,10 @@
namespace icsneo {
class MDIOMessage : public Frame {
class MDIOMessage : public BusMessage {
public:
const BusMessage::Type getBusType() const final { return BusMessage::Type::MDIO; }
enum class Clause : uint8_t {
Clause45 = 0,
Clause22 = 1

View File

@ -7,14 +7,70 @@ typedef uint16_t neomessagetype_t;
#ifdef __cplusplus
#include "icsneo/communication/network.h"
#include "icsneo/icsneoc2types.h"
#include <vector>
#include <sstream>
#include <string>
namespace icsneo {
class Message {
/**
* @brief Type of message class
*
* @see AbstractMessage::getMsgType()
*/
typedef enum class MessageType : icsneoc2_msg_type_t {
Device = icsneoc2_msg_type_device,
Internal = icsneoc2_msg_type_internal,
Bus = icsneoc2_msg_type_bus,
MaxSize = icsneoc2_msg_type_maxsize,
} MessageType;
/**
* @brief Pure virtual abstract class for all messages. Inherit from Message over this class.
*
* @see Message
*
*/
class AbstractMessage {
public:
virtual const MessageType getMsgType() const = 0;
};
/**
* @brief Base Message class representing Device messages.
*/
class Message : public AbstractMessage {
public:
virtual const MessageType getMsgType() const { return MessageType::Device; }
/**
* @brief Get the string representation of the message type
*
* @return String representation of the message type
*
* @see AbstractMessage::getMsgType()
*/
static std::string getMsgTypeName(MessageType msgType) {
switch (msgType) {
case MessageType::Device:
return "Device";
case MessageType::Internal:
return "Internal";
case MessageType::Bus:
return "Bus";
// Don't default here so we can rely on the compiler to warn us about missing cases
};
std::stringstream ss;
ss << "Unknown (" << static_cast<int>(msgType) << ")";
return ss.str();
}
enum class Type : neomessagetype_t {
Frame = 0,
BusMessage = 0,
// Deprecated: Will be removed in the future.
Frame = BusMessage,
CANErrorCount = 0x100,
CANError = 0x100,
@ -24,7 +80,9 @@ public:
// Past 0x8000 are all for internal use only
Invalid = 0x8000,
RawMessage = 0x8001,
InternalMessage = 0x8001,
// Deprecated: Will be removed in the future.
RawMessage = InternalMessage,
ReadSettings = 0x8002,
ResetStatus = 0x8003,
DeviceVersion = 0x8004,
@ -52,26 +110,69 @@ public:
uint64_t timestamp = 0;
};
class RawMessage : public Message {
/**
* @brief Internal Message class representing Device messages that shouldn't be exposed to public APIs.
*/
class InternalMessage : public Message {
public:
RawMessage(Message::Type type = Message::Type::RawMessage) : Message(type) {}
RawMessage(Message::Type type, Network net) : Message(type), network(net) {}
RawMessage(Network net) : Message(Message::Type::RawMessage), network(net) {}
RawMessage(Network net, std::vector<uint8_t> d) : Message(Message::Type::RawMessage), network(net), data(d) {}
InternalMessage(Message::Type type = Message::Type::InternalMessage) : Message(type) {}
InternalMessage(Message::Type type, Network net) : Message(type), network(net) {}
InternalMessage(Network net) : Message(Message::Type::InternalMessage), network(net) {}
InternalMessage(Network net, std::vector<uint8_t> d) : Message(Message::Type::InternalMessage), network(net), data(d) {}
virtual const MessageType getMsgType() const { return MessageType::Internal; }
Network network;
std::vector<uint8_t> data;
};
class Frame : public RawMessage {
/**
* @brief Bus Message class representing Device messages representing Bus networks like CAN, LIN, Ethernet, etc.
*/
class BusMessage : public InternalMessage {
public:
Frame() : RawMessage(Message::Type::Frame) {}
BusMessage() : InternalMessage(Message::Type::BusMessage) {}
/** @brief
* Bus message types, useful for filtering out or identifying Bus Messages.
*/
typedef enum class Type : icsneoc2_msg_bus_type_t {
Invalid = icsneoc2_msg_bus_type_invalid,
Internal = icsneoc2_msg_bus_type_internal,
CAN = icsneoc2_msg_bus_type_can,
LIN = icsneoc2_msg_bus_type_lin,
FlexRay = icsneoc2_msg_bus_type_flexray,
MOST = icsneoc2_msg_bus_type_most,
Ethernet = icsneoc2_msg_bus_type_ethernet,
LSFTCAN = icsneoc2_msg_bus_type_lsftcan,
SWCAN = icsneoc2_msg_bus_type_swcan,
ISO9141 = icsneoc2_msg_bus_type_iso9141,
I2C = icsneoc2_msg_bus_type_i2c,
A2B = icsneoc2_msg_bus_type_a2b,
SPI = icsneoc2_msg_bus_type_spi,
MDIO = icsneoc2_msg_bus_type_mdio,
ANY = icsneoc2_msg_bus_type_any,
OTHER = icsneoc2_msg_bus_type_other
} Type;
const MessageType getMsgType() const final { return MessageType::Bus; }
virtual const BusMessage::Type getBusType() const = 0;
// Description ID of the message. This is used for filtering / tracking in firmware and driver.
// This is equivalent to icsSpyMessage::DescriptionID
uint16_t description = 0;
// weather the message was originally transmitted on the bus. This is equivalent to
// SPY_STATUS_TX_MSG bit field in icsSpyMessage::StatusBitField
bool transmitted = false;
bool error = false;
};
/** @brief Backwards compatibility, RawMessage was renamed to better reflect what it actually does. */
typedef InternalMessage RawMessage;
/** @brief Backwards compatibility, Frame was renamed to better reflect what it actually does. */
typedef BusMessage Frame;
}
#endif // __cplusplus

View File

@ -7,9 +7,9 @@
namespace icsneo {
class NeoReadMemorySDMessage : public RawMessage {
class NeoReadMemorySDMessage : public InternalMessage {
public:
NeoReadMemorySDMessage() : RawMessage(Message::Type::RawMessage, Network::NetID::NeoMemorySDRead) {}
NeoReadMemorySDMessage() : InternalMessage(Message::Type::InternalMessage, Network::NetID::NeoMemorySDRead) {}
uint32_t startAddress = 0;
};

View File

@ -8,9 +8,9 @@
namespace icsneo {
class ReadSettingsMessage : public RawMessage {
class ReadSettingsMessage : public InternalMessage {
public:
ReadSettingsMessage() : RawMessage(Message::Type::ReadSettings, Network::NetID::ReadSettings) {}
ReadSettingsMessage() : InternalMessage(Message::Type::ReadSettings, Network::NetID::ReadSettings) {}
enum class Response : uint8_t {
OK = 0,

View File

@ -12,6 +12,8 @@ typedef uint8_t neonettype_t;
#include <optional>
#include <tuple>
#include <icsneo/icsneoc2types.h>
namespace icsneo {
class Network {
@ -23,187 +25,187 @@ class Network {
static constexpr uint16_t OFFSET_PLASMA_SLAVE3_RANGE2 = 12800;
public:
enum class NetID : neonetid_t {
Device = 0,
HSCAN = 1,
MSCAN = 2,
SWCAN = 3,
LSFTCAN = 4,
FordSCP = 5,
J1708 = 6,
Aux = 7,
J1850VPW = 8,
ISO9141 = 9,
DiskData = 10,
Main51 = 11,
RED = 12,
SCI = 13,
ISO9141_2 = 14,
ISO14230 = 15,
LIN = 16,
OP_Ethernet1 = 17,
OP_Ethernet2 = 18,
OP_Ethernet3 = 19,
enum class NetID : icsneoc2_netid_t {
Device = icsneoc2_netid_device,
HSCAN = icsneoc2_netid_hscan,
MSCAN = icsneoc2_netid_mscan,
SWCAN = icsneoc2_netid_swcan,
LSFTCAN = icsneoc2_netid_lsftcan,
FordSCP = icsneoc2_netid_fordscp,
J1708 = icsneoc2_netid_j1708,
Aux = icsneoc2_netid_aux,
J1850VPW = icsneoc2_netid_j1850vpw,
ISO9141 = icsneoc2_netid_iso9141,
DiskData = icsneoc2_netid_disk_data,
Main51 = icsneoc2_netid_main51,
RED = icsneoc2_netid_red,
SCI = icsneoc2_netid_sci,
ISO9141_2 = icsneoc2_netid_iso9141_2,
ISO14230 = icsneoc2_netid_iso14230,
LIN = icsneoc2_netid_lin,
OP_Ethernet1 = icsneoc2_netid_op_ethernet1,
OP_Ethernet2 = icsneoc2_netid_op_ethernet2,
OP_Ethernet3 = icsneoc2_netid_op_ethernet3,
// START Device Command Returns
// When we send a command, the device returns on one of these, depending on command
RED_EXT_MEMORYREAD = 20,
RED_INT_MEMORYREAD = 21,
RED_DFLASH_READ = 22,
NeoMemorySDRead = 23, // Response from NeoMemory (MemoryTypeSD)
CAN_ERRBITS = 24,
NeoMemoryWriteDone = 25,
RED_WAVE_CAN1_LOGICAL = 26,
RED_WAVE_CAN2_LOGICAL = 27,
RED_WAVE_LIN1_LOGICAL = 28,
RED_WAVE_LIN2_LOGICAL = 29,
RED_WAVE_LIN1_ANALOG = 30,
RED_WAVE_LIN2_ANALOG = 31,
RED_WAVE_MISC_ANALOG = 32,
RED_WAVE_MISCDIO2_LOGICAL = 33,
RED_NETWORK_COM_ENABLE_EX = 34,
RED_NEOVI_NETWORK = 35,
RED_READ_BAUD_SETTINGS = 36,
RED_OLDFORMAT = 37,
RED_SCOPE_CAPTURE = 38,
RED_HARDWARE_EXCEP = 39,
RED_GET_RTC = 40,
RED_EXT_MEMORYREAD = icsneoc2_netid_red_ext_memoryread,
RED_INT_MEMORYREAD = icsneoc2_netid_red_int_memoryread,
RED_DFLASH_READ = icsneoc2_netid_red_dflash_read,
NeoMemorySDRead = icsneoc2_netid_neo_memory_sdread, // Response from NeoMemory (MemoryTypeSD)
CAN_ERRBITS = icsneoc2_netid_can_errbits,
NeoMemoryWriteDone = icsneoc2_netid_neo_memory_write_done,
RED_WAVE_CAN1_LOGICAL = icsneoc2_netid_red_wave_can1_logical,
RED_WAVE_CAN2_LOGICAL = icsneoc2_netid_red_wave_can2_logical,
RED_WAVE_LIN1_LOGICAL = icsneoc2_netid_red_wave_lin1_logical,
RED_WAVE_LIN2_LOGICAL = icsneoc2_netid_red_wave_lin2_logical,
RED_WAVE_LIN1_ANALOG = icsneoc2_netid_red_wave_lin1_analog,
RED_WAVE_LIN2_ANALOG = icsneoc2_netid_red_wave_lin2_analog,
RED_WAVE_MISC_ANALOG = icsneoc2_netid_red_wave_misc_analog,
RED_WAVE_MISCDIO2_LOGICAL = icsneoc2_netid_red_wave_miscdio2_logical,
RED_NETWORK_COM_ENABLE_EX = icsneoc2_netid_red_network_com_enable_ex,
RED_NEOVI_NETWORK = icsneoc2_netid_red_neovi_network,
RED_READ_BAUD_SETTINGS = icsneoc2_netid_red_read_baud_settings,
RED_OLDFORMAT = icsneoc2_netid_red_oldformat,
RED_SCOPE_CAPTURE = icsneoc2_netid_red_scope_capture,
RED_HARDWARE_EXCEP = icsneoc2_netid_red_hardware_excep,
RED_GET_RTC = icsneoc2_netid_red_get_rtc,
// END Device Command Returns
ISO9141_3 = 41,
HSCAN2 = 42,
HSCAN3 = 44,
OP_Ethernet4 = 45,
OP_Ethernet5 = 46,
ISO9141_4 = 47,
LIN2 = 48,
LIN3 = 49,
LIN4 = 50,
ISO9141_3 = icsneoc2_netid_iso9141_3,
HSCAN2 = icsneoc2_netid_hscan2,
HSCAN3 = icsneoc2_netid_hscan3,
OP_Ethernet4 = icsneoc2_netid_op_ethernet4,
OP_Ethernet5 = icsneoc2_netid_op_ethernet5,
ISO9141_4 = icsneoc2_netid_iso9141_4,
LIN2 = icsneoc2_netid_lin2,
LIN3 = icsneoc2_netid_lin3,
LIN4 = icsneoc2_netid_lin4,
// MOST = 51, Old and unused
RED_App_Error = 52,
CGI = 53,
Reset_Status = 54,
FB_Status = 55,
App_Signal_Status = 56,
Read_Datalink_Cm_Tx_Msg = 57,
Read_Datalink_Cm_Rx_Msg = 58,
Logging_Overflow = 59,
ReadSettings = 60,
HSCAN4 = 61,
HSCAN5 = 62,
RS232 = 63,
UART = 64,
UART2 = 65,
UART3 = 66,
UART4 = 67,
SWCAN2 = 68,
Ethernet_DAQ = 69,
Data_To_Host = 70,
TextAPI_To_Host = 71,
SPI1 = 72,
OP_Ethernet6 = 73,
Red_VBat = 74,
OP_Ethernet7 = 75,
OP_Ethernet8 = 76,
OP_Ethernet9 = 77,
OP_Ethernet10 = 78,
OP_Ethernet11 = 79,
FlexRay1a = 80,
FlexRay1b = 81,
FlexRay2a = 82,
FlexRay2b = 83,
LIN5 = 84,
FlexRay = 85,
FlexRay2 = 86,
OP_Ethernet12 = 87,
I2C = 88,
MOST25 = 90,
MOST50 = 91,
MOST150 = 92,
Ethernet = 93,
GMFSA = 94,
TCP = 95,
HSCAN6 = 96,
HSCAN7 = 97,
LIN6 = 98,
LSFTCAN2 = 99,
LogicalDiskInfo = 187,
WiVICommand = 221,
ScriptStatus = 224,
EthPHYControl = 239,
ExtendedCommand = 240,
ExtendedData = 242,
FlexRayControl = 243,
CoreMiniPreLoad = 244,
HW_COM_Latency_Test = 512,
DeviceStatus = 513,
UDP = 514,
ForwardedMessage = 516,
I2C2 = 517,
I2C3 = 518,
I2C4 = 519,
Ethernet2 = 520,
A2B1 = 522,
A2B2 = 523,
Ethernet3 = 524,
WBMS = 532,
DWCAN9 = 534,
DWCAN10 = 535,
DWCAN11 = 536,
DWCAN12 = 537,
DWCAN13 = 538,
DWCAN14 = 539,
DWCAN15 = 540,
DWCAN16 = 541,
LIN7 = 542,
LIN8 = 543,
SPI2 = 544,
MDIO1 = 545,
MDIO2 = 546,
MDIO3 = 547,
MDIO4 = 548,
MDIO5 = 549,
MDIO6 = 550,
MDIO7 = 551,
MDIO8 = 552,
OP_Ethernet13 = 553,
OP_Ethernet14 = 554,
OP_Ethernet15 = 555,
OP_Ethernet16 = 556,
SPI3 = 557,
SPI4 = 558,
SPI5 = 559,
SPI6 = 560,
SPI7 = 561,
SPI8 = 562,
LIN9 = 563,
LIN10 = 564,
LIN11 = 565,
LIN12 = 566,
LIN13 = 567,
LIN14 = 568,
LIN15 = 569,
LIN16 = 570,
Any = 0xfffe, // Never actually set as type, but used as flag for filtering
Invalid = 0xffff
RED_App_Error = icsneoc2_netid_red_app_error,
CGI = icsneoc2_netid_cgi,
Reset_Status = icsneoc2_netid_reset_status,
FB_Status = icsneoc2_netid_fb_status,
App_Signal_Status = icsneoc2_netid_app_signal_status,
Read_Datalink_Cm_Tx_Msg = icsneoc2_netid_read_datalink_cm_tx_msg,
Read_Datalink_Cm_Rx_Msg = icsneoc2_netid_read_datalink_cm_rx_msg,
Logging_Overflow = icsneoc2_netid_logging_overflow,
ReadSettings = icsneoc2_netid_read_settings,
HSCAN4 = icsneoc2_netid_hscan4,
HSCAN5 = icsneoc2_netid_hscan5,
RS232 = icsneoc2_netid_rs232,
UART = icsneoc2_netid_uart,
UART2 = icsneoc2_netid_uart2,
UART3 = icsneoc2_netid_uart3,
UART4 = icsneoc2_netid_uart4,
SWCAN2 = icsneoc2_netid_swcan2,
Ethernet_DAQ = icsneoc2_netid_ethernet_daq,
Data_To_Host = icsneoc2_netid_data_to_host,
TextAPI_To_Host = icsneoc2_netid_textapi_to_host,
SPI1 = icsneoc2_netid_spi1,
OP_Ethernet6 = icsneoc2_netid_op_ethernet6,
Red_VBat = icsneoc2_netid_red_vbat,
OP_Ethernet7 = icsneoc2_netid_op_ethernet7,
OP_Ethernet8 = icsneoc2_netid_op_ethernet8,
OP_Ethernet9 = icsneoc2_netid_op_ethernet9,
OP_Ethernet10 = icsneoc2_netid_op_ethernet10,
OP_Ethernet11 = icsneoc2_netid_op_ethernet11,
FlexRay1a = icsneoc2_netid_flexray1a,
FlexRay1b = icsneoc2_netid_flexray1b,
FlexRay2a = icsneoc2_netid_flexray2a,
FlexRay2b = icsneoc2_netid_flexray2b,
LIN5 = icsneoc2_netid_lin5,
FlexRay = icsneoc2_netid_flexray,
FlexRay2 = icsneoc2_netid_flexray2,
OP_Ethernet12 = icsneoc2_netid_op_ethernet12,
I2C = icsneoc2_netid_i2c,
MOST25 = icsneoc2_netid_most25,
MOST50 = icsneoc2_netid_most50,
MOST150 = icsneoc2_netid_most150,
Ethernet = icsneoc2_netid_ethernet,
GMFSA = icsneoc2_netid_gmfsa,
TCP = icsneoc2_netid_tcp,
HSCAN6 = icsneoc2_netid_hscan6,
HSCAN7 = icsneoc2_netid_hscan7,
LIN6 = icsneoc2_netid_lin6,
LSFTCAN2 = icsneoc2_netid_lsftcan2,
LogicalDiskInfo = icsneoc2_netid_logical_disk_info,
WiVICommand = icsneoc2_netid_wivi_command,
ScriptStatus = icsneoc2_netid_script_status,
EthPHYControl = icsneoc2_netid_eth_phy_control,
ExtendedCommand = icsneoc2_netid_extended_command,
ExtendedData = icsneoc2_netid_extended_data,
FlexRayControl = icsneoc2_netid_flexray_control,
CoreMiniPreLoad = icsneoc2_netid_coremini_preload,
HW_COM_Latency_Test = icsneoc2_netid_hw_com_latency_test,
DeviceStatus = icsneoc2_netid_device_status,
UDP = icsneoc2_netid_udp,
ForwardedMessage = icsneoc2_netid_forwarded_message,
I2C2 = icsneoc2_netid_i2c2,
I2C3 = icsneoc2_netid_i2c3,
I2C4 = icsneoc2_netid_i2c4,
Ethernet2 = icsneoc2_netid_ethernet2,
A2B1 = icsneoc2_netid_a2b1,
A2B2 = icsneoc2_netid_a2b2,
Ethernet3 = icsneoc2_netid_ethernet3,
WBMS = icsneoc2_netid_wbms,
DWCAN9 = icsneoc2_netid_dwcan9,
DWCAN10 = icsneoc2_netid_dwcan10,
DWCAN11 = icsneoc2_netid_dwcan11,
DWCAN12 = icsneoc2_netid_dwcan12,
DWCAN13 = icsneoc2_netid_dwcan13,
DWCAN14 = icsneoc2_netid_dwcan14,
DWCAN15 = icsneoc2_netid_dwcan15,
DWCAN16 = icsneoc2_netid_dwcan16,
LIN7 = icsneoc2_netid_lin7,
LIN8 = icsneoc2_netid_lin8,
SPI2 = icsneoc2_netid_spi2,
MDIO1 = icsneoc2_netid_mdio1,
MDIO2 = icsneoc2_netid_mdio2,
MDIO3 = icsneoc2_netid_mdio3,
MDIO4 = icsneoc2_netid_mdio4,
MDIO5 = icsneoc2_netid_mdio5,
MDIO6 = icsneoc2_netid_mdio6,
MDIO7 = icsneoc2_netid_mdio7,
MDIO8 = icsneoc2_netid_mdio8,
OP_Ethernet13 = icsneoc2_netid_op_ethernet13,
OP_Ethernet14 = icsneoc2_netid_op_ethernet14,
OP_Ethernet15 = icsneoc2_netid_op_ethernet15,
OP_Ethernet16 = icsneoc2_netid_op_ethernet16,
SPI3 = icsneoc2_netid_spi3,
SPI4 = icsneoc2_netid_spi4,
SPI5 = icsneoc2_netid_spi5,
SPI6 = icsneoc2_netid_spi6,
SPI7 = icsneoc2_netid_spi7,
SPI8 = icsneoc2_netid_spi8,
LIN9 = icsneoc2_netid_lin9,
LIN10 = icsneoc2_netid_lin10,
LIN11 = icsneoc2_netid_lin11,
LIN12 = icsneoc2_netid_lin12,
LIN13 = icsneoc2_netid_lin13,
LIN14 = icsneoc2_netid_lin14,
LIN15 = icsneoc2_netid_lin15,
LIN16 = icsneoc2_netid_lin16,
Any = icsneoc2_netid_any, // Never actually set as type, but used as flag for filtering
Invalid = icsneoc2_netid_invalid
};
enum class Type : neonettype_t {
Invalid = 0,
Internal = 1, // Used for statuses that don't actually need to be transferred to the client application
CAN = 2,
LIN = 3,
FlexRay = 4,
MOST = 5,
Ethernet = 6,
LSFTCAN = 7,
SWCAN = 8,
ISO9141 = 9,
I2C = 10,
A2B = 11,
SPI = 12,
MDIO = 13,
Any = 0xFE, // Never actually set as type, but used as flag for filtering
Other = 0xFF
enum class Type : icsneoc2_msg_bus_type_t {
Invalid = icsneoc2_msg_bus_type_invalid,
Internal = icsneoc2_msg_bus_type_internal, // Used for statuses that don't actually need to be transferred to the client application
CAN = icsneoc2_msg_bus_type_can,
LIN = icsneoc2_msg_bus_type_lin,
FlexRay = icsneoc2_msg_bus_type_flexray,
MOST = icsneoc2_msg_bus_type_most,
Ethernet = icsneoc2_msg_bus_type_ethernet,
LSFTCAN = icsneoc2_msg_bus_type_lsftcan,
SWCAN = icsneoc2_msg_bus_type_swcan,
ISO9141 = icsneoc2_msg_bus_type_iso9141,
I2C = icsneoc2_msg_bus_type_i2c,
A2B = icsneoc2_msg_bus_type_a2b,
SPI = icsneoc2_msg_bus_type_spi,
MDIO = icsneoc2_msg_bus_type_mdio,
Any = icsneoc2_msg_bus_type_any, // Never actually set as type, but used as flag for filtering
Other = icsneoc2_msg_bus_type_other
};
enum class CoreMini : uint8_t {
HSCAN = 0,

View File

@ -13,6 +13,9 @@ namespace icsneo {
typedef uint16_t icscm_bitfield;
std::optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd);
std::optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd);
#pragma pack(push,2)
struct HardwareCANPacket {
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);

View File

@ -213,8 +213,8 @@ public:
int addMessageCallback(const std::shared_ptr<MessageCallback>& cb) { return com->addMessageCallback(cb); }
bool removeMessageCallback(int id) { return com->removeMessageCallback(id); }
bool transmit(std::shared_ptr<Frame> frame);
bool transmit(std::vector<std::shared_ptr<Frame>> frames);
bool transmit(std::shared_ptr<BusMessage> frame);
bool transmit(std::vector<std::shared_ptr<BusMessage>> frames);
void setWriteBlocks(bool blocks);
@ -839,7 +839,7 @@ protected:
void handleInternalMessage(std::shared_ptr<Message> message);
virtual void handleDeviceStatus(const std::shared_ptr<RawMessage>&) {}
virtual void handleDeviceStatus(const std::shared_ptr<InternalMessage>&) {}
neodevice_t& getWritableNeoDevice() { return data; }

View File

@ -14,7 +14,9 @@ typedef uint32_t devicetype_t;
#include <ostream>
#include <cstdint>
typedef uint32_t devicetype_t;
#include <icsneo/icsneoc2types.h>
typedef icsneoc2_devicetype_t devicetype_t;
namespace icsneo {
@ -22,65 +24,65 @@ class DeviceType {
public:
// This enum used to be a bitfield, but has since become an enum as we have more than 32 devices
// Adding something? Make sure you update the type string and C-compatible defines below!
enum Enum : devicetype_t {
Unknown = (0x00000000),
BLUE = (0x00000001),
ECU_AVB = (0x00000002),
RADSupermoon = (0x00000003),
DW_VCAN = (0x00000004),
RADMoon2 = (0x00000005),
RADMars = (0x00000006),
VCAN4_1 = (0x00000007),
FIRE = (0x00000008),
RADPluto = (0x00000009),
VCAN4_2EL = (0x0000000a),
RADIO_CANHUB = (0x0000000b),
NEOECU12 = (0x0000000c),
OBD2_LCBADGE = (0x0000000d),
RADMoonDuo = (0x0000000e),
FIRE3 = (0x0000000f),
VCAN3 = (0x00000010),
RADJupiter = (0x00000011),
VCAN4_IND = (0x00000012),
RADGigastar = (0x00000013),
RED2 = (0x00000014),
EtherBADGE = (0x00000016),
RAD_A2B = (0x00000017),
RADEpsilon = (0x00000018),
RADGalaxy2 = (0x00000021),
RADMoon3 = (0x00000023),
RADComet = (0x00000024),
FIRE3_FlexRay = (0x00000025),
Connect = (0x00000026),
RADComet3 = (0x00000027),
RADMoonT1S = (0x00000028),
RADGigastar2 = (0x00000029),
RED = (0x00000040),
ECU = (0x00000080),
IEVB = (0x00000100),
Pendant = (0x00000200),
OBD2_PRO = (0x00000400),
ECUChip_UART = (0x00000800),
PLASMA = (0x00001000),
DONT_REUSE0 = (0x00002000), // Previously FIRE_VNET
NEOAnalog = (0x00004000),
CT_OBD = (0x00008000),
DONT_REUSE1 = (0x00010000), // Previously PLASMA_1_12
DONT_REUSE2 = (0x00020000), // Previously PLASMA_1_13
ION = (0x00040000),
RADStar = (0x00080000),
DONT_REUSE3 = (0x00100000), // Previously ION3
VCAN4_4 = (0x00200000),
VCAN4_2 = (0x00400000),
CMProbe = (0x00800000),
EEVB = (0x01000000),
VCANrf = (0x02000000),
FIRE2 = (0x04000000),
Flex = (0x08000000),
RADGalaxy = (0x10000000),
RADStar2 = (0x20000000),
VividCAN = (0x40000000),
OBD2_SIM = (0x80000000)
enum Enum : icsneoc2_devicetype_t {
Unknown = icsneoc2_devicetype_unknown,
BLUE = icsneoc2_devicetype_blue,
ECU_AVB = icsneoc2_devicetype_ecu_avb,
RADSupermoon = icsneoc2_devicetype_rad_supermoon,
DW_VCAN = icsneoc2_devicetype_dw_vcan,
RADMoon2 = icsneoc2_devicetype_rad_moon2,
RADMars = icsneoc2_devicetype_rad_mars,
VCAN4_1 = icsneoc2_devicetype_vcan41,
FIRE = icsneoc2_devicetype_fire,
RADPluto = icsneoc2_devicetype_rad_pluto,
VCAN4_2EL = icsneoc2_devicetype_vcan42_el,
RADIO_CANHUB = icsneoc2_devicetype_radio_canhub,
NEOECU12 = icsneoc2_devicetype_neo_ecu12,
OBD2_LCBADGE = icsneoc2_devicetype_obd2_lc_badge,
RADMoonDuo = icsneoc2_devicetype_rad_moon_duo,
FIRE3 = icsneoc2_devicetype_fire3,
VCAN3 = icsneoc2_devicetype_vcan3,
RADJupiter = icsneoc2_devicetype_rad_jupiter,
VCAN4_IND = icsneoc2_devicetype_vcan4_industrial,
RADGigastar = icsneoc2_devicetype_rad_gigastar,
RED2 = icsneoc2_devicetype_red2,
EtherBADGE = icsneoc2_devicetype_etherbadge,
RAD_A2B = icsneoc2_devicetype_rad_a2b,
RADEpsilon = icsneoc2_devicetype_rad_epsilon,
RADGalaxy2 = icsneoc2_devicetype_rad_galaxy2,
RADMoon3 = icsneoc2_devicetype_rad_moon3,
RADComet = icsneoc2_devicetype_rad_comet,
FIRE3_FlexRay = icsneoc2_devicetype_fire3_flexray,
Connect = icsneoc2_devicetype_connect,
RADComet3 = icsneoc2_devicetype_rad_comet3,
RADMoonT1S = icsneoc2_devicetype_rad_moon_t1s,
RADGigastar2 = icsneoc2_devicetype_rad_gigastar2,
RED = icsneoc2_devicetype_red,
ECU = icsneoc2_devicetype_ecu,
IEVB = icsneoc2_devicetype_ievb,
Pendant = icsneoc2_devicetype_pendant,
OBD2_PRO = icsneoc2_devicetype_obd2_pro,
ECUChip_UART = icsneoc2_devicetype_ecuchip_uart,
PLASMA = icsneoc2_devicetype_plasma,
//DONT_REUSE0 = , // Previously FIRE_VNET
NEOAnalog = icsneoc2_devicetype_neo_analog,
CT_OBD = icsneoc2_devicetype_ct_obd,
//DONT_REUSE1 = (0x00010000), // Previously PLASMA_1_12
//DONT_REUSE2 = (0x00020000), // Previously PLASMA_1_13
ION = icsneoc2_devicetype_ion,
RADStar = icsneoc2_devicetype_rad_star,
//DONT_REUSE3 = (0x00100000), // Previously ION3
VCAN4_4 = icsneoc2_devicetype_vcan44,
VCAN4_2 = icsneoc2_devicetype_vcan42,
CMProbe = icsneoc2_devicetype_cm_probe,
EEVB = icsneoc2_devicetype_eevb,
VCANrf = icsneoc2_devicetype_vcan_rf,
FIRE2 = icsneoc2_devicetype_fire2,
Flex = icsneoc2_devicetype_flex,
RADGalaxy = icsneoc2_devicetype_rad_galaxy,
RADStar2 = icsneoc2_devicetype_rad_star2,
VividCAN = icsneoc2_devicetype_vividcan,
OBD2_SIM = icsneoc2_devicetype_obd2_sim
};
/**
@ -90,9 +92,10 @@ public:
* as the product name may change based on device-specific factors, such as serial
* number.
*/
static const char* GetGenericProductName(DeviceType::Enum type) {
template<typename T>
static std::string GetGenericProductName(T deviceType) {
// Adding something? Make sure you update DEVICE_TYPE_LONGEST_NAME at the top!
switch(type) {
switch(static_cast<icsneoc2_devicetype_t>(deviceType)) {
case Unknown:
return "Unknown";
case BLUE:
@ -201,12 +204,7 @@ public:
return "neoVI Connect";
case RADGigastar2:
return "RAD-Gigastar 2";
case DONT_REUSE0:
case DONT_REUSE1:
case DONT_REUSE2:
case DONT_REUSE3:
// Intentionally don't use default so that the compiler throws a warning when something is added
return "Unknown neoVI";
// Intentionally don't use default so that the compiler throws a warning when something is added
}
return "Unknown neoVI";
}
@ -214,8 +212,8 @@ public:
DeviceType() { value = DeviceType::Enum::Unknown; }
DeviceType(devicetype_t netid) { value = (DeviceType::Enum)netid; }
DeviceType(DeviceType::Enum netid) { value = netid; }
DeviceType::Enum getDeviceType() const { return value; }
std::string getGenericProductName() const { return GetGenericProductName(getDeviceType()); }
icsneoc2_devicetype_t getDeviceType() const { return value; }
std::string getGenericProductName() const { return DeviceType::GetGenericProductName(getDeviceType()); }
operator devicetype_t() const { return getDeviceType(); }
private:

View File

@ -33,7 +33,7 @@ public:
virtual void handleMessage(const std::shared_ptr<Message>&) {}
// Return true to continue transmitting, success should be written to if false is returned
virtual bool transmitHook(const std::shared_ptr<Frame>& frame, bool& success) { (void)frame; (void)success; return true; }
virtual bool transmitHook(const std::shared_ptr<BusMessage>& frame, bool& success) { (void)frame; (void)success; return true; }
protected:
Device& device;

View File

@ -25,7 +25,7 @@ public:
void onGoOffline() override;
void handleMessage(const std::shared_ptr<Message>& message) override;
bool transmitHook(const std::shared_ptr<Frame>& frame, bool& success) override;
bool transmitHook(const std::shared_ptr<BusMessage>& frame, bool& success) override;
std::shared_ptr<Controller> getController(uint8_t index) const {
if(index >= controllers.size())

View File

@ -121,7 +121,7 @@ protected:
// The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(neovifire2_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -81,7 +81,7 @@ protected:
return ret;
}
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(fire2vnet_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -92,7 +92,7 @@ protected:
// The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(radgalaxy_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -97,7 +97,7 @@ protected:
// The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(radgalaxy2_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -105,7 +105,7 @@ protected:
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
}
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(radgigastar_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -113,7 +113,7 @@ namespace icsneo
// The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network> &txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<RawMessage> &message) override
void handleDeviceStatus(const std::shared_ptr<InternalMessage> &message) override
{
if (message->data.size() < sizeof(radgigastar2_status_t))
return;

View File

@ -97,7 +97,7 @@ protected:
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
}
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(radmars_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -75,7 +75,7 @@ protected:
size_t getEthernetActivationLineCount() const override { return 1; }
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
void handleDeviceStatus(const std::shared_ptr<InternalMessage>& message) override {
if(message->data.size() < sizeof(valuecan4_2el_status_t))
return;
std::lock_guard<std::mutex> lk(ioMutex);

View File

@ -0,0 +1,740 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <icsneo/icsneoc2types.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32) || defined(_WIN64)
// Microsoft
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#elif defined(__GNUC__)
// GCC
#define EXPORT __attribute__((visibility("default")))
#define IMPORT
#else
// do nothing and hope for the best?
#define EXPORT
#define IMPORT
#pragma warning Unknown dynamic link import/export semantics.
#endif
#ifdef ICSNEOC2_BUILD_STATIC
#define ICSNEOC2_API
#else
#ifdef ICSNEOC2_BUILD_DYNAMIC
#define ICSNEOC2_API EXPORT
#else
#define ICSNEOC2_API IMPORT
#endif // ICSNEOC2_BUILD_DYNAMIC
#endif // ICSNEOC2_BUILD_STATIC
/** @brief icsneoc2_device_t opaque struct definition
*
* This object represents a single device found on the system.
*
* @see icsneo_find_devices
*/
typedef struct icsneoc2_device_t icsneoc2_device_t;
/** @brief icsneoc2_message_t opaque struct definition
*
* This object represents a single event from the device.
*
* @see icsneoc2_device_events_get
*/
typedef struct icsneoc2_message_t icsneoc2_message_t;
/** @brief icsneoc2_event_t opaque struct definition
*
* This object represents a single event from the device.
*
* @see icsneoc2_device_events_get
*/
typedef struct icsneoc2_event_t icsneoc2_event_t;
/** @brief Error codes for icsneo functions.
*
* This enum is guaranteed to be ABI stable, any new values will be appended to the end.
*/
typedef enum _icsneoc2_error_t {
// Function was successful
icsneoc2_error_success,
// Invalid parameters, typically because of a NULL reference.
icsneoc2_error_invalid_parameters,
// Error opening the device.
icsneoc2_error_open_failed,
// Error going online.
icsneoc2_error_go_online_failed,
// Error enabling message polling.
icsneoc2_error_enable_message_polling_failed,
// Error syncing RTC.
icsneoc2_error_sync_rtc_failed,
// Error getting messages.
icsneoc2_error_get_messages_failed,
// Generic invalid type error
icsneoc2_error_invalid_type,
// Generic RTC error code
icsneoc2_error_rtc_failure,
// Error setting settings
icsneoc2_error_set_settings_failure,
// Failed to transmit messages
icsneoc2_error_transmit_messages_failed,
// Failed to copy string to buffer
icsneoc2_error_string_copy_failed,
// Invalid device parameter
icsneoc2_error_invalid_device,
// Invalid message parameter
icsneoc2_error_invalid_message,
// NOTE: Any new values added here should be updated in icsneoc2_error_code_get
} _icsneoc2_error_t;
/** @brief Integer representation of _icsneoc2_error_t enum.
*
* This is used for easier ABI compatibility, especially between other languages.
*/
typedef uint32_t icsneoc2_error_t;
/** @brief Get the error string for an error code.
*
* @param[in] icsneoc2_error_t error_code The error code to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_error_code_get(icsneoc2_error_t error_code, const char* value, uint32_t* value_length);
/** @brief Get the device type string for a icsneoc2_devicetype_t.
*
* @param[in] icsneoc2_devicetype_t device_type The device type to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_type_name_get(icsneoc2_devicetype_t device_type, const char* value, uint32_t* value_length);
/** @brief Find all hardware attached to the system.
*
* @param[out] icsneoc2_device_t array of devices to be filled with found devices.
* Undefined behaviour if index is out of range of devices_count.
* @param[in,out] uint32_t* devices_count Size of the devices array. Modified with the number of devices found.
* @param[in] void* reserved Reserved for future use. Currently unused and must be set to NULL.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_find_all(icsneoc2_device_t** devices, uint32_t* devices_count, void* reserved);
/** @brief Check to make sure a device is valid.
*
* @param[in] icsneoc2_device_t device The device to check.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_is_valid(icsneoc2_device_t* device);
/** @brief Check to make sure a device is open.
*
* @param[in] icsneoc2_device_t device The device to check.
* @param[out] bool is_open true if the device is open, false otherwise
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_is_open(icsneoc2_device_t* device, bool* is_open);
/** @brief Check see if a device is disconnected.
*
* @param[in] icsneoc2_device_t device The device to check.
* @param[out] bool is_disconnected true if the device is open, false otherwise
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_is_disconnected(icsneoc2_device_t* device, bool* is_disconnected);
/** @brief Get the open options for a device
*
* @param[in] icsneoc2_device_t device The device to set options for.
* @param[in] icsneoc2_open_options_t options Options to set for the device.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_open_options_get(icsneoc2_device_t* device, icsneoc2_open_options_t* options);
/** @brief Set the open options for a device
*
* @param[in] icsneoc2_device_t device The device to set options for.
* @param[in] icsneoc2_open_options_t options Options to set for the device.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_open_options_set(icsneoc2_device_t* device, icsneoc2_open_options_t options);
/** @brief Open a connection to a device.
*
* After a successful call to this function, icsneoc2_device_close() must be called to close the device.
*
* @param[in] icsneoc2_device_t device The device to open.
* @param[out] icsneo_handle_t* handle Pointer to a handle to the opened device. Will be NULL on failure.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_failure otherwise.
*
* @see icsneoc2_device_close
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_open(icsneoc2_device_t* device);
/** @brief Close a connection to a previously opened device.
*
* After a successful call to icsneoc2_device_open(), this function must be called to close the device.
* An already closed device will still succeed. All messages and events related to the device will be freed.
*
* @param[in] icsneoc2_device_t device The device to close.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_failure otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_close(icsneoc2_device_t* device);
/** @brief Get the description of a device
*
* @param[in] icsneoc2_device_t device The device to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_description_get(icsneoc2_device_t* device, const char* value, uint32_t* value_length);
/** @brief Get the type of a device
*
* @param[in] icsneoc2_device_t device The device to get the type of.
* @param[out] icsneoc2_devicetype_t* value Pointer to an icsneoc2_devicetype_t to copy the type into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_type_get(icsneoc2_device_t* device, icsneoc2_devicetype_t* value);
/** @brief Get the serial of a device
*
* @param[in] icsneoc2_device_t device The device to get the serial of.
* @param[out] const char* value Pointer to a buffer to copy the serial into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the serial.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_serial_get(icsneoc2_device_t* device, const char* value, uint32_t* value_length);
/** @brief Set the online state of a device.
*
* @param[in] icsneoc2_device_t device The device to set the online state of.
* @param[in] bool go_online true to go online, false to go offline.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_go_online(icsneoc2_device_t* device, bool go_online);
/** @brief Get the online state of a device.
*
* @param[in] icsneoc2_device_t device The device to get the online state of.
* @param[out] bool true if online, false if offline.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_is_online(icsneoc2_device_t* device, bool* is_online);
/** @brief Get the online supported state of a device.
*
* @param[in] icsneoc2_device_t device The device to get the online supported state of.
* @param[out] bool true if online, false if offline.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_is_online_supported(icsneoc2_device_t* device, bool* is_online_supported);
/** @brief Set the message polling state of a device.
*
* @param[in] icsneoc2_device_t device The device to set the message polling state of.
* @param[in] bool enable true to enable message polling, false to disable message polling..
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_message_polling_set(icsneoc2_device_t* device, bool enable);
/** @brief Get the message polling state of a device.
*
* @param[in] icsneoc2_device_t device The device to set the message polling state of.
* @param[out] bool is_enabled true if message polling is enabled, false if message polling is disabled.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_message_polling_get(icsneoc2_device_t* device, bool* is_enabled);
/** @brief Set the message polling limit of a device.
*
* This will truncate the message queue to the specified limit.
*
* @param[in] icsneoc2_device_t device The device to enforce the message polling limit.
* @param[in] uint32_t limit The limit to enforce.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_message_polling_set_limit(icsneoc2_device_t* device, uint32_t limit);
/** @brief Get the message polling limit of a device.
*
* @see icsneoc2_device_message_polling_set_limit
*
* @param[in] icsneoc2_device_t device The device to enforce the message polling limit.
* @param[out] uint32_t limit The limit to get.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_message_polling_limit_get(icsneoc2_device_t* device, uint32_t* limit);
/** @brief Get the message count of a device
*
* @param[in] icsneoc2_device_t device The device to get the message count of.
* @param[out] uint32_t* count Pointer to a uint32_t to copy the message count into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_message_count_get(icsneoc2_device_t* device, uint32_t* count);
/** @brief Get the timestamp resolution (nanoseconds) of a device
*
* @param[in] icsneoc2_device_t device The device to get the timestamp resolution of.
* @param[out] uint32_t* resolution Pointer to a uint32_t to copy the timestamp resolution in nanoseconds into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_timestamp_resolution_get(icsneoc2_device_t* device, uint32_t* resolution);
/** @brief Get the messages of a device
*
* When calling this function, the previous messages retrieved by this function will be invalid.
*
* @param[in] icsneoc2_device_t device The device to get the messages of.
* @param[out] icsneoc2_message_t** messages Pointer to an array of icsneoc2_message_t to copy the messages into.
* Undefined behaviour if index is out of range of messages_count.
* @param[in,out] uint32_t* messages_count Size of the messages array. Modified with the number of messages found.
* @param[in] uint32_t timeout_ms The timeout in milliseconds to wait for messages. A value of 0 indicates a non-blocking call.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_messages_get(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t* messages_count, uint32_t timeout_ms);
/** @brief Transmit messages from a device
*
* @param[in] icsneoc2_device_t device The device to get the messages of.
* @param[out] icsneoc2_message_t** messages Pointer to an array of icsneoc2_message_t to copy the messages into.
* Undefined behaviour if index is out of range of messages_count.
* @param[in,out] uint32_t* messages_count Size of the messages array. Modified with the number of messages actually transmitted.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_transmission_failed otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_messages_transmit(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t* messages_count);
/** @brief Check if a message is valid
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] bool* is_valid Pointer to a bool to copy the validity of the message into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_is_valid(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* is_valid);
/** @brief Get the type of a message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] icsneoc2_msg_type_t* msg_type Pointer to a icsneoc2_msg_type_t to copy the type of the value into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*
* @see icsneoc2_msg_type_t
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_type_get(icsneoc2_device_t* device, icsneoc2_message_t* message, icsneoc2_msg_type_t* msg_type);
/** @brief Get the message type string for a icsneoc2_msg_bus_type_t.
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_type_name_get(icsneoc2_msg_type_t msg_type, const char* value, uint32_t* value_length);
/** @brief Get the type of a bus message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] icsneoc2_msg_type_t* msg_type Pointer to a icsneoc2_msg_type_t to copy the type of the value into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*
* @see icsneoc2_msg_bus_type_t, icsneoc2_bus_type_name_get
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_bus_type_get(icsneoc2_device_t* device, icsneoc2_message_t* message, icsneoc2_msg_bus_type_t* bus_type);
/** @brief Get the bus type string for a icsneoc2_msg_bus_type_t.
*
* @param[in] icsneoc2_msg_bus_type_t bus_type The bus type to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_bus_type_name_get(icsneoc2_msg_bus_type_t bus_type, const char* value, uint32_t* value_length);
/** @brief Get the transmission status of a message.
*
* When a message is transmitted from the device, It will be returned in the receive buffer.
* @see icsneoc2_device_messages_transmit
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to modify.
* @param[out] bool value Pointer to a bool to copy the tranmission status into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_is_transmit(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Get the Network ID (netid) of a bus message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] icsneoc2_netid_t* netid Pointer to a icsneoc2_netid_t to copy the type of the value into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*
* @see icsneoc2_netid_t, icsneoc2_netid_name_get
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_netid_get(icsneoc2_device_t* device, icsneoc2_message_t* message, icsneoc2_netid_t* netid);
/** @brief Get the netid string for a icsneoc2_netid_t.
*
* @param[in] icsneoc2_netid_t netid The network id to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_netid_name_get(icsneoc2_netid_t netid, const char* value, uint32_t* value_length);
/** @brief Set the Network ID (netid) of a bus message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[in] icsneoc2_netid_t netid The netid to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_netid_set(icsneoc2_device_t* device, icsneoc2_message_t* message, icsneoc2_netid_t netid);
/** @brief Set the data bytes of a message
*
* @note This function will not set the DLC of the message. @see icsneoc2_message_set_dlc
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to copy the data into.
* @param[out] uint8_t* data Pointer to a uint8_t array to copy from.
* @param[in] uint32_t data_length length of the data.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_data_set(icsneoc2_device_t* device, icsneoc2_message_t* message, uint8_t* data, uint32_t data_length);
/** @brief Get the data bytes of a message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] uint8_t* data Pointer to a uint8_t to copy the data bytes into.
* @param[in,out] uint32_t* data_length Pointer to a uint32_t to copy the length of the data into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_data_get(icsneoc2_device_t* device, icsneoc2_message_t* message, uint8_t* data, uint32_t* data_length);
/** @brief Get the Arbitration ID of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] uint32_t* value Pointer to a uint32_t to copy the Arbitration ID into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_arbid_get(icsneoc2_device_t* device, icsneoc2_message_t* message, uint32_t* value);
/** @brief Set the Arbitration ID of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] uint32_t value Arbitration ID to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_arbid_set(icsneoc2_device_t* device, icsneoc2_message_t* message, uint32_t value);
/** @brief Get the DLC on wire of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] uint32_t* value Pointer to a uint32_t to copy the DLC on wire into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_dlc_get(icsneoc2_device_t* device, icsneoc2_message_t* message, int32_t* value);
/** @brief Set the DLC on wire of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] int32_t value DLC to set. Set to a negative value to auto calculate. Auto setting assumes data and
* canfd parameters are correct. Set to 0 on failure. @see icsneoc2_message_can_set_data and icsneoc2_message_can_canfd_set
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_dlc_set(icsneoc2_device_t* device, icsneoc2_message_t* message, int32_t value);
/** @brief Get the Remote Transmission Request (RTR) status of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[in] int32_t value DLC to get.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_is_remote(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Set the Remote Transmission Request (RTR) of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to modify.
* @param[out] bool value Remote status to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_set_remote(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Get the extended status of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] bool* value Pointer to a uint32_t to copy the extended status into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_is_extended(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Set the extended status of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to modify.
* @param[out] bool value Extended status to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_extended_set(icsneoc2_device_t* device, icsneoc2_message_t* message, bool value);
/** @brief Get the CANFD status of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] bool* value Pointer to a uint32_t to copy the CANFD status into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_is_canfd(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Set the CANFD status of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to modify.
* @param[out] bool value CANFD status to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_canfd_set(icsneoc2_device_t* device, icsneoc2_message_t* message, bool value);
/** @brief Get the baudrate switch status (BRS) of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] bool* value Pointer to a uint32_t to copy the baudrate switch (BRS) status into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_baudrate_switch_get(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Set the baudrate switch status (BRS) of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to modify.
* @param[out] bool value baudrate switch status (BRS) to set.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_baudrate_switch_set(icsneoc2_device_t* device, icsneoc2_message_t* message, bool value);
/** @brief Get the error state indicator status of a CAN message
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[in] icsneoc2_message_t* message The message to check.
* @param[out] bool* value Pointer to a uint32_t to copy the error state indicator status into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_error_state_indicator_get(icsneoc2_device_t* device, icsneoc2_message_t* message, bool* value);
/** @brief Create CAN messages for a device
*
* @param[in] icsneoc2_device_t device The device to get the messages of.
* @param[out] icsneoc2_message_t** messages Pointer to an array of icsneoc2_message_t to copy the messages into.
* Undefined behaviour if index is out of range of messages_count.
* @param[in] uint32_t* messages_count Size of the messages array.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_create(icsneoc2_device_t* device, icsneoc2_message_t** messages, uint32_t messages_count);
/** @brief Free CAN messages for a device
*
* @param[in] icsneoc2_device_t device The device to free the messages of.
* @param[in] icsneoc2_message_t* message The message to free.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*
* @warning This function should only be called on messages created by icsneoc2_message_can_create.
*
* @see icsneoc2_message_can_create
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_message_can_free(icsneoc2_device_t* device, icsneoc2_message_t* message);
/** @brief Get the global events not specifically related to a device.
*
* @param[out] icsneoc2_event_t** events Pointer to an array of icsneoc2_event_t to copy the events into.
* Undefined behaviour if index is out of range of events_count.
* @param[in,out] uint32_t* events_count Size of the events array. Modified with the number of events found.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_events_get(icsneoc2_event_t** events, uint32_t* events_count);
/** @brief Get the events of a device.
*
* @param[in] icsneoc2_device_t device The device to get the events of.
* @param[out] icsneoc2_event_t** events Pointer to an array of icsneoc2_event_t to copy the events into.
* Undefined behaviour if index is out of range of events_count.
* @param[in,out] uint32_t* events_count Size of the events array. Modified with the number of events found.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_events_get(icsneoc2_device_t* device, icsneoc2_event_t** events, uint32_t* events_count);
/** @brief Get the error string for an error code.
*
* @param[in] icsneoc2_event_t* event The event to get the description of.
* @param[out] const char* value Pointer to a buffer to copy the description into. Null terminated.
* @param[in,out] uint32_t* value_length Size of the value buffer. Modified with the length of the description.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_event_description_get(icsneoc2_event_t* event, const char* value, uint32_t* value_length);
/** @brief Get the RTC (Real time clock) of a device.
*
* @param[in] icsneoc2_device_t device The device to get the RTC of.
* @param[out] int64_t* unix_epoch Pointer to an int64_t to copy the RTC into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_rtc_get(icsneoc2_device_t* device, int64_t* unix_epoch);
/** @brief Set the RTC (Real time clock) of a device.
*
* @param[in] icsneoc2_device_t device The device to get the RTC of.
* @param[in] int64_t unix_epoch int64_t to copy the RTC into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_rtc_set(icsneoc2_device_t* device, int64_t unix_epoch);
/** @brief Load the default settings for a device
*
* @param[in] icsneoc2_device_t device The device to load the settings for.
* @param[in] bool save True to make the settings permanent, false will be reverted on power cycle.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_load_default_settings(icsneoc2_device_t* device, bool save);
/** @brief Get the baudrate for a network
*
* @note @see icsneoc2_device_canfd_baudrate_get for CANFD.
*
* @param[in] icsneoc2_device_t* device The device to get the baudrate value.
* @param[in] icsneoc2_netid_t netid The network to get the baudrate value.
* @param[in] uint64_t* baudrate The baudrate to get the network value.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_baudrate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint64_t* baudrate);
/** @brief Set the baudrate for a network
*
* @note @see icsneoc2_device_canfd_baudrate_set for CANFD.
*
* @param[in] icsneoc2_device_t* device The device to set the baudrate for.
* @param[in] icsneoc2_netid_t netid The network to set the baudrate for.
* @param[in] uint64_t baudrate The baudrate to set the network to.
* @param[in] bool save True to make the settings permanent, false will be reverted on power cycle.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_baudrate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint64_t baudrate, bool save);
/** @brief Get the baudrate for a CAN FD network
*
* @param[in] icsneoc2_device_t* device The device to get the baudrate value.
* @param[in] icsneoc2_netid_t netid The network to get the baudrate value.
* @param[in] uint64_t* baudrate The baudrate to get the network value.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_canfd_baudrate_get(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint64_t* baudrate);
/** @brief Set the baudrate for a CANFD network
*
* @param[in] icsneoc2_device_t* device The device to set the baudrate for.
* @param[in] icsneoc2_netid_t netid The network to set the baudrate for.
* @param[in] uint64_t baudrate The baudrate to set the network to.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_canfd_baudrate_set(icsneoc2_device_t* device, icsneoc2_netid_t netid, uint64_t baudrate, bool save);
/** @brief Check if the device supports TC10.
*
* @param[in] icsneoc2_device_t* device The device to check against.
* @param[out] bool* supported Pointer to a uint32_t to copy the value into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
ICSNEOC2_API icsneoc2_error_t icsneoc2_device_supports_tc10(icsneoc2_device_t* device, bool* supported);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,382 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/** @brief
* Options for opening a device. See icsneoc2_device_open() for more info.
*/
typedef enum _icsneoc2_open_options_t {
// No options
icsneoc2_open_options_none = 0x0,
// After opening, go online
icsneoc2_open_options_go_online = 0x1,
// After opening, enable message polling
icsneoc2_open_options_enable_message_polling = 0x2,
// After opening, sync RTC
icsneoc2_open_options_sync_rtc = 0x4,
// After opening, enable auto update
icsneoc2_open_options_enable_auto_update = 0x8,
// After opening, force update
icsneoc2_open_options_force_update = 0x10,
} _icsneoc2_open_options_t;
/** @brief Integer representation of _icsneoc2_open_options_t enum.
*
* This is used for easier ABI compatibility, especially between other languages.
*/
typedef uint32_t icsneoc2_open_options_t;
/** @brief
* Intrepid hardware device types, useful for filtering out or identifying devices.
*/
typedef enum _icsneoc2_devicetype_t {
// Unknown device type
icsneoc2_devicetype_unknown,
// neoVI Blue - Obsolete
icsneoc2_devicetype_blue,
// neoECU AVB/TSN
icsneoc2_devicetype_ecu_avb,
// RAD-SuperMoon
icsneoc2_devicetype_rad_supermoon,
// DualWire ValueCAN - Obsolete
icsneoc2_devicetype_dw_vcan,
// RAD-Moon 2
icsneoc2_devicetype_rad_moon2,
// RAD-Mars
icsneoc2_devicetype_rad_mars,
// ValueCAN 4-1
icsneoc2_devicetype_vcan41,
// neoVI FIRE
icsneoc2_devicetype_fire,
// RAD-Pluto
icsneoc2_devicetype_rad_pluto,
// ValueCAN 4-2EL
icsneoc2_devicetype_vcan42_el,
// RAD-IO CAN-HUB
icsneoc2_devicetype_radio_canhub,
// neoECU12
icsneoc2_devicetype_neo_ecu12,
// neoOBD2-LC Badge
icsneoc2_devicetype_obd2_lc_badge,
// RAD-Moon Duo
icsneoc2_devicetype_rad_moon_duo,
// neoVI FIRE3
icsneoc2_devicetype_fire3,
// ValueCAN3
icsneoc2_devicetype_vcan3,
// RAD-Jupiter
icsneoc2_devicetype_rad_jupiter,
// ValueCAN4 Industrial
icsneoc2_devicetype_vcan4_industrial,
// RAD-Gigastar
icsneoc2_devicetype_rad_gigastar,
// neoVI RED2
icsneoc2_devicetype_red2,
// EtherBADGE
icsneoc2_devicetype_etherbadge,
// RAD-A2B
icsneoc2_devicetype_rad_a2b,
// RAD-Epsilon
icsneoc2_devicetype_rad_epsilon,
// RAD-Moon 3
icsneoc2_devicetype_rad_moon3,
// RAD-Comet
icsneoc2_devicetype_rad_comet,
// neoVI FIRE3 FlexRay
icsneoc2_devicetype_fire3_flexray,
// neoVI CONNECT
icsneoc2_devicetype_connect,
// RAD-Comet 3
icsneoc2_devicetype_rad_comet3,
// RAD-Moon T1S
icsneoc2_devicetype_rad_moon_t1s,
// RAD-Gigastar 2
icsneoc2_devicetype_rad_gigastar2,
// neoVI RED
icsneoc2_devicetype_red,
// neoECU - Obsolete
icsneoc2_devicetype_ecu,
// IEVB - Obsolete
icsneoc2_devicetype_ievb,
// Pendant - Obsolete
icsneoc2_devicetype_pendant,
// neoOBD2 Pro - Obsolete
icsneoc2_devicetype_obd2_pro,
// neoECU Chip - Obsolete
icsneoc2_devicetype_ecuchip_uart,
// neoVI PLASMA
icsneoc2_devicetype_plasma,
// neoAnalog - Obsolete
icsneoc2_devicetype_neo_analog,
// Obsolete
icsneoc2_devicetype_ct_obd,
// neoVI ION
icsneoc2_devicetype_ion,
// RAD-Star - Obsolete
icsneoc2_devicetype_rad_star,
// ValueCAN4-4
icsneoc2_devicetype_vcan44,
// ValueCAN4-2
icsneoc2_devicetype_vcan42,
// CMProbe - Obsolete
icsneoc2_devicetype_cm_probe,
// Ethernet EVB - Obsolete
icsneoc2_devicetype_eevb,
// ValueCAN.rf - Obsolete
icsneoc2_devicetype_vcan_rf,
// neoVI FIRE2
icsneoc2_devicetype_fire2,
// neoVI FLEX - Obsolete
icsneoc2_devicetype_flex,
// RAD-Galaxy
icsneoc2_devicetype_rad_galaxy,
// RAD-Star 2
icsneoc2_devicetype_rad_star2,
// VividCAN
icsneoc2_devicetype_vividcan,
// neoOBD2 SIM
icsneoc2_devicetype_obd2_sim,
// RAD-Galaxy 2
icsneoc2_devicetype_rad_galaxy2,
// Must be last entry
icsneoc2_devicetype_maxsize,
} _icsneoc2_devicetype_t;
/** @brief Integer representation of _icsneoc2_devicetype_t enum.
*
* This is used for easier ABI compatibility, especially between other languages.
*/
typedef uint32_t icsneoc2_devicetype_t;
typedef enum _icsneoc2_msg_type_t {
icsneoc2_msg_type_device,
icsneoc2_msg_type_internal,
icsneoc2_msg_type_bus,
icsneoc2_msg_type_maxsize,
} _icsneoc2_msg_type_t;
/** @brief Integer representation of _icsneoc2_msg_type_t enum.
*
* This is used for easier ABI compatibility, especially between other languages.
*/
typedef uint32_t icsneoc2_msg_type_t;
/** @brief
* Bus message types, useful for filtering out or identifying Bus Messages.
*/
typedef enum _icsneoc2_msg_bus_type_t {
icsneoc2_msg_bus_type_invalid = 0,
icsneoc2_msg_bus_type_internal = 1, // Used for statuses that don't actually need to be transferred to the client application
icsneoc2_msg_bus_type_can = 2,
icsneoc2_msg_bus_type_lin = 3,
icsneoc2_msg_bus_type_flexray = 4,
icsneoc2_msg_bus_type_most = 5,
icsneoc2_msg_bus_type_ethernet = 6,
icsneoc2_msg_bus_type_lsftcan = 7,
icsneoc2_msg_bus_type_swcan = 8,
icsneoc2_msg_bus_type_iso9141 = 9,
icsneoc2_msg_bus_type_i2c = 10,
icsneoc2_msg_bus_type_a2b = 11,
icsneoc2_msg_bus_type_spi = 12,
icsneoc2_msg_bus_type_mdio = 13,
// Must be last entry
icsneoc2_msg_bus_type_maxsize,
icsneoc2_msg_bus_type_any = 0xFE, // Never actually set as type, but used as flag for filtering
icsneoc2_msg_bus_type_other = 0xFF
} _icsneoc2_msg_bus_type_t;
/** @brief Integer representation of _icsneoc2_msg_bus_type_t enum.
*
* This is used for easier ABI compatibility, especially between other languages.
*/
typedef uint8_t icsneoc2_msg_bus_type_t;
typedef enum _icsneoc2_netid_t {
icsneoc2_netid_device = 0,
icsneoc2_netid_hscan = 1,
icsneoc2_netid_mscan = 2,
icsneoc2_netid_swcan = 3,
icsneoc2_netid_lsftcan = 4,
icsneoc2_netid_fordscp = 5,
icsneoc2_netid_j1708 = 6,
icsneoc2_netid_aux = 7,
icsneoc2_netid_j1850vpw = 8,
icsneoc2_netid_iso9141 = 9,
icsneoc2_netid_disk_data = 10,
icsneoc2_netid_main51 = 11,
icsneoc2_netid_red = 12,
icsneoc2_netid_sci = 13,
icsneoc2_netid_iso9141_2 = 14,
icsneoc2_netid_iso14230 = 15,
icsneoc2_netid_lin = 16,
icsneoc2_netid_op_ethernet1 = 17,
icsneoc2_netid_op_ethernet2 = 18,
icsneoc2_netid_op_ethernet3 = 19,
// START Device Command Returns
// When we send a command, the device returns on one of these, depending on command
icsneoc2_netid_red_ext_memoryread = 20,
icsneoc2_netid_red_int_memoryread = 21,
icsneoc2_netid_red_dflash_read = 22,
icsneoc2_netid_neo_memory_sdread = 23, // Response from NeoMemory (MemoryTypeSD)
icsneoc2_netid_can_errbits = 24,
icsneoc2_netid_neo_memory_write_done = 25,
icsneoc2_netid_red_wave_can1_logical = 26,
icsneoc2_netid_red_wave_can2_logical = 27,
icsneoc2_netid_red_wave_lin1_logical = 28,
icsneoc2_netid_red_wave_lin2_logical = 29,
icsneoc2_netid_red_wave_lin1_analog = 30,
icsneoc2_netid_red_wave_lin2_analog = 31,
icsneoc2_netid_red_wave_misc_analog = 32,
icsneoc2_netid_red_wave_miscdio2_logical = 33,
icsneoc2_netid_red_network_com_enable_ex = 34,
icsneoc2_netid_red_neovi_network = 35,
icsneoc2_netid_red_read_baud_settings = 36,
icsneoc2_netid_red_oldformat = 37,
icsneoc2_netid_red_scope_capture = 38,
icsneoc2_netid_red_hardware_excep = 39,
icsneoc2_netid_red_get_rtc = 40,
// END Device Command Returns
icsneoc2_netid_iso9141_3 = 41,
icsneoc2_netid_hscan2 = 42,
icsneoc2_netid_hscan3 = 44,
icsneoc2_netid_op_ethernet4 = 45,
icsneoc2_netid_op_ethernet5 = 46,
icsneoc2_netid_iso9141_4 = 47,
icsneoc2_netid_lin2 = 48,
icsneoc2_netid_lin3 = 49,
icsneoc2_netid_lin4 = 50,
icsneoc2_netid_most_unused = 51, // MOST = 51, Old and unused
icsneoc2_netid_red_app_error = 52,
icsneoc2_netid_cgi = 53,
icsneoc2_netid_reset_status = 54,
icsneoc2_netid_fb_status = 55,
icsneoc2_netid_app_signal_status = 56,
icsneoc2_netid_read_datalink_cm_tx_msg = 57,
icsneoc2_netid_read_datalink_cm_rx_msg = 58,
icsneoc2_netid_logging_overflow = 59,
icsneoc2_netid_read_settings = 60,
icsneoc2_netid_hscan4 = 61,
icsneoc2_netid_hscan5 = 62,
icsneoc2_netid_rs232 = 63,
icsneoc2_netid_uart = 64,
icsneoc2_netid_uart2 = 65,
icsneoc2_netid_uart3 = 66,
icsneoc2_netid_uart4 = 67,
icsneoc2_netid_swcan2 = 68,
icsneoc2_netid_ethernet_daq = 69,
icsneoc2_netid_data_to_host = 70,
icsneoc2_netid_textapi_to_host = 71,
icsneoc2_netid_spi1 = 72,
icsneoc2_netid_op_ethernet6 = 73,
icsneoc2_netid_red_vbat = 74,
icsneoc2_netid_op_ethernet7 = 75,
icsneoc2_netid_op_ethernet8 = 76,
icsneoc2_netid_op_ethernet9 = 77,
icsneoc2_netid_op_ethernet10 = 78,
icsneoc2_netid_op_ethernet11 = 79,
icsneoc2_netid_flexray1a = 80,
icsneoc2_netid_flexray1b = 81,
icsneoc2_netid_flexray2a = 82,
icsneoc2_netid_flexray2b = 83,
icsneoc2_netid_lin5 = 84,
icsneoc2_netid_flexray = 85,
icsneoc2_netid_flexray2 = 86,
icsneoc2_netid_op_ethernet12 = 87,
icsneoc2_netid_i2c = 88,
icsneoc2_netid_most25 = 90,
icsneoc2_netid_most50 = 91,
icsneoc2_netid_most150 = 92,
icsneoc2_netid_ethernet = 93,
icsneoc2_netid_gmfsa = 94,
icsneoc2_netid_tcp = 95,
icsneoc2_netid_hscan6 = 96,
icsneoc2_netid_hscan7 = 97,
icsneoc2_netid_lin6 = 98,
icsneoc2_netid_lsftcan2 = 99,
icsneoc2_netid_logical_disk_info = 187,
icsneoc2_netid_wivi_command = 221,
icsneoc2_netid_script_status = 224,
icsneoc2_netid_eth_phy_control = 239,
icsneoc2_netid_extended_command = 240,
icsneoc2_netid_extended_data = 242,
icsneoc2_netid_flexray_control = 243,
icsneoc2_netid_coremini_preload = 244,
icsneoc2_netid_hw_com_latency_test = 512,
icsneoc2_netid_device_status = 513,
icsneoc2_netid_udp = 514,
icsneoc2_netid_forwarded_message = 516,
icsneoc2_netid_i2c2 = 517,
icsneoc2_netid_i2c3 = 518,
icsneoc2_netid_i2c4 = 519,
icsneoc2_netid_ethernet2 = 520,
icsneoc2_netid_a2b1 = 522,
icsneoc2_netid_a2b2 = 523,
icsneoc2_netid_ethernet3 = 524,
icsneoc2_netid_wbms = 532,
icsneoc2_netid_dwcan9 = 534,
icsneoc2_netid_dwcan10 = 535,
icsneoc2_netid_dwcan11 = 536,
icsneoc2_netid_dwcan12 = 537,
icsneoc2_netid_dwcan13 = 538,
icsneoc2_netid_dwcan14 = 539,
icsneoc2_netid_dwcan15 = 540,
icsneoc2_netid_dwcan16 = 541,
icsneoc2_netid_lin7 = 542,
icsneoc2_netid_lin8 = 543,
icsneoc2_netid_spi2 = 544,
icsneoc2_netid_mdio1 = 545,
icsneoc2_netid_mdio2 = 546,
icsneoc2_netid_mdio3 = 547,
icsneoc2_netid_mdio4 = 548,
icsneoc2_netid_mdio5 = 549,
icsneoc2_netid_mdio6 = 550,
icsneoc2_netid_mdio7 = 551,
icsneoc2_netid_mdio8 = 552,
icsneoc2_netid_op_ethernet13 = 553,
icsneoc2_netid_op_ethernet14 = 554,
icsneoc2_netid_op_ethernet15 = 555,
icsneoc2_netid_op_ethernet16 = 556,
icsneoc2_netid_spi3 = 557,
icsneoc2_netid_spi4 = 558,
icsneoc2_netid_spi5 = 559,
icsneoc2_netid_spi6 = 560,
icsneoc2_netid_spi7 = 561,
icsneoc2_netid_spi8 = 562,
icsneoc2_netid_lin9 = 563,
icsneoc2_netid_lin10 = 564,
icsneoc2_netid_lin11 = 565,
icsneoc2_netid_lin12 = 566,
icsneoc2_netid_lin13 = 567,
icsneoc2_netid_lin14 = 568,
icsneoc2_netid_lin15 = 569,
icsneoc2_netid_lin16 = 570,
// Must be the last entry
icsneoc2_netid_maxsize,
icsneoc2_netid_any = 0xfffe, // Never actually set as type, but used as flag for filtering
icsneoc2_netid_invalid = 0xffff
} _icsneoc2_netid_t;
/** @brief Integer representation of _icsneoc2_netid_t enum.
*
* This is used for easier ABI compatibility, especially between other languages.
*/
typedef uint16_t icsneoc2_netid_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,453 @@
#include <gtest/gtest.h>
#include <icsneo/icsneoc2.h>
#include <vector>
#include <tuple>
TEST(icsneoc2, test_icsneoc2_device_find_all) {
const auto MAX_DEV_SIZE = 255;
icsneoc2_device_t* devices[MAX_DEV_SIZE] = {0};
uint32_t devices_count = MAX_DEV_SIZE;
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_find_all(NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_find_all(devices, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_find_all(NULL, &devices_count, NULL));
ASSERT_EQ(icsneoc2_error_success, icsneoc2_device_find_all(devices, &devices_count, NULL));
for (uint32_t i=0; i < MAX_DEV_SIZE; ++i) {
if (i < devices_count) {
ASSERT_EQ(icsneoc2_error_success, icsneoc2_device_is_valid(devices[i]));
} else {
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_valid(devices[i]));
}
}
}
TEST(icsneoc2, test_icsneoc2_is_device) {
icsneoc2_device_t* invalid_device = static_cast<icsneoc2_device_t*>((void*)0x1234);
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_is_valid(NULL));
ASSERT_EQ(icsneoc2_error_invalid_device, icsneoc2_device_is_valid(invalid_device));
}
TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device) {
bool placeholderBool = false;
uint32_t placeholderInteger32 = 0;
uint64_t placeholderInteger64 = 0;
const char placeholderStr[255] = {0};
icsneoc2_event_t* eventPlaceHolder = nullptr;
// All of these don't have a device parameter
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_find_all(NULL, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_bus_type_name_get(0, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_event_description_get(eventPlaceHolder, placeholderStr, &placeholderInteger32));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_events_get(NULL, &placeholderInteger32));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_type_name_get(0, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_error_code_get(0, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_message_type_name_get(0, NULL, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_netid_name_get(0, NULL, NULL));
// Test everything with a device and with a device with a bad pointer
std::vector<std::tuple<_icsneoc2_error_t, icsneoc2_device_t*>> testPatterns = {
{ icsneoc2_error_invalid_parameters, NULL},
{ icsneoc2_error_invalid_device, static_cast<icsneoc2_device_t*>((void*)0x1234)},
};
for (const auto& testPattern : testPatterns) {
const auto& errorCode = std::get<0>(testPattern);
const auto& device = std::get<1>(testPattern);
ASSERT_EQ(errorCode, icsneoc2_device_baudrate_get(device, 0, &placeholderInteger64));
ASSERT_EQ(errorCode, icsneoc2_device_baudrate_set(device, 0, 0, placeholderInteger64));
ASSERT_EQ(errorCode, icsneoc2_device_canfd_baudrate_get(device, 0, &placeholderInteger64));
ASSERT_EQ(errorCode, icsneoc2_device_canfd_baudrate_set(device, 0, 0, placeholderInteger64));
ASSERT_EQ(errorCode, icsneoc2_device_close(device));
ASSERT_EQ(errorCode, icsneoc2_device_description_get(device, placeholderStr, &placeholderInteger32));
ASSERT_EQ(errorCode, icsneoc2_device_go_online(device, false));
ASSERT_EQ(errorCode, icsneoc2_device_is_online(device, &placeholderBool));
ASSERT_EQ(errorCode, icsneoc2_device_is_online_supported(device, &placeholderBool));
ASSERT_EQ(errorCode, icsneoc2_device_is_valid(device));
ASSERT_EQ(errorCode, icsneoc2_device_is_open(device, &placeholderBool));
ASSERT_EQ(errorCode, icsneoc2_device_is_disconnected(device, &placeholderBool));
ASSERT_EQ(errorCode, icsneoc2_device_load_default_settings(device, false));
ASSERT_EQ(errorCode, icsneoc2_device_open(device));
ASSERT_EQ(errorCode, icsneoc2_device_open_options_get(device, &placeholderInteger32));
ASSERT_EQ(errorCode, icsneoc2_device_open_options_set(device, 0));
ASSERT_EQ(errorCode, icsneoc2_device_rtc_get(device, (int64_t*)&placeholderInteger64));
ASSERT_EQ(errorCode, icsneoc2_device_rtc_set(device, 0));
ASSERT_EQ(errorCode, icsneoc2_device_serial_get(device, placeholderStr, &placeholderInteger32));
ASSERT_EQ(errorCode, icsneoc2_device_supports_tc10(device, &placeholderBool));
ASSERT_EQ(errorCode, icsneoc2_device_timestamp_resolution_get(device, &placeholderInteger32));
ASSERT_EQ(errorCode, icsneoc2_device_type_get(device, NULL));
ASSERT_EQ(errorCode, icsneoc2_device_message_count_get(device, &placeholderInteger32));
ASSERT_EQ(errorCode, icsneoc2_device_message_polling_get(device, &placeholderBool));
ASSERT_EQ(errorCode, icsneoc2_device_message_polling_limit_get(device, &placeholderInteger32));
ASSERT_EQ(errorCode, icsneoc2_device_message_polling_set(device, false));
ASSERT_EQ(errorCode, icsneoc2_device_message_polling_set_limit(device, 0));
ASSERT_EQ(errorCode, icsneoc2_device_messages_get(device, NULL, NULL, 0));
ASSERT_EQ(errorCode, icsneoc2_device_messages_transmit(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_bus_type_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_arbid_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_arbid_set(device, NULL, 0));
ASSERT_EQ(errorCode, icsneoc2_message_can_baudrate_switch_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_baudrate_switch_set(device, NULL, false));
ASSERT_EQ(errorCode, icsneoc2_message_can_canfd_set(device, NULL, false));
ASSERT_EQ(errorCode, icsneoc2_message_can_create(device, NULL, 0));
ASSERT_EQ(errorCode, icsneoc2_message_can_dlc_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_dlc_set(device, NULL, 0));
ASSERT_EQ(errorCode, icsneoc2_message_can_error_state_indicator_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_extended_set(device, NULL, false));
ASSERT_EQ(errorCode, icsneoc2_message_can_free(device, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_is_canfd(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_is_extended(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_can_is_remote(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_data_get(device, NULL, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_data_set(device, NULL, NULL, 0));
ASSERT_EQ(errorCode, icsneoc2_message_is_transmit(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_is_valid(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_netid_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_message_netid_set(device, NULL, 0));
ASSERT_EQ(errorCode, icsneoc2_message_type_get(device, NULL, NULL));
ASSERT_EQ(errorCode, icsneoc2_device_events_get(device, NULL, NULL));
}
}
TEST(icsneoc2, test_icsneoc2_devicetype_t) {
std::vector<_icsneoc2_devicetype_t> devicetypeValues = {
// Unknown device type
icsneoc2_devicetype_unknown,
// neoVI Blue - Obsolete
icsneoc2_devicetype_blue,
// neoECU AVB/TSN
icsneoc2_devicetype_ecu_avb,
// RAD-SuperMoon
icsneoc2_devicetype_rad_supermoon,
// DualWire ValueCAN - Obsolete
icsneoc2_devicetype_dw_vcan,
// RAD-Moon 2
icsneoc2_devicetype_rad_moon2,
// RAD-Mars
icsneoc2_devicetype_rad_mars,
// ValueCAN 4-1
icsneoc2_devicetype_vcan41,
// neoVI FIRE
icsneoc2_devicetype_fire,
// RAD-Pluto
icsneoc2_devicetype_rad_pluto,
// ValueCAN 4-2EL
icsneoc2_devicetype_vcan42_el,
// RAD-IO CAN-HUB
icsneoc2_devicetype_radio_canhub,
// neoECU12
icsneoc2_devicetype_neo_ecu12,
// neoOBD2-LC Badge
icsneoc2_devicetype_obd2_lc_badge,
// RAD-Moon Duo
icsneoc2_devicetype_rad_moon_duo,
// neoVI FIRE3
icsneoc2_devicetype_fire3,
// ValueCAN3
icsneoc2_devicetype_vcan3,
// RAD-Jupiter
icsneoc2_devicetype_rad_jupiter,
// ValueCAN4 Industrial
icsneoc2_devicetype_vcan4_industrial,
// RAD-Gigastar
icsneoc2_devicetype_rad_gigastar,
// neoVI RED2
icsneoc2_devicetype_red2,
// EtherBADGE
icsneoc2_devicetype_etherbadge,
// RAD-A2B
icsneoc2_devicetype_rad_a2b,
// RAD-Epsilon
icsneoc2_devicetype_rad_epsilon,
// RAD-Moon 3
icsneoc2_devicetype_rad_moon3,
// RAD-Comet
icsneoc2_devicetype_rad_comet,
// neoVI FIRE3 FlexRay
icsneoc2_devicetype_fire3_flexray,
// neoVI CONNECT
icsneoc2_devicetype_connect,
// RAD-Comet 3
icsneoc2_devicetype_rad_comet3,
// RAD-Moon T1S
icsneoc2_devicetype_rad_moon_t1s,
// RAD-Gigastar 2
icsneoc2_devicetype_rad_gigastar2,
// neoVI RED
icsneoc2_devicetype_red,
// neoECU - Obsolete
icsneoc2_devicetype_ecu,
// IEVB - Obsolete
icsneoc2_devicetype_ievb,
// Pendant - Obsolete
icsneoc2_devicetype_pendant,
// neoOBD2 Pro - Obsolete
icsneoc2_devicetype_obd2_pro,
// neoECU Chip - Obsolete
icsneoc2_devicetype_ecuchip_uart,
// neoVI PLASMA
icsneoc2_devicetype_plasma,
// neoAnalog - Obsolete
icsneoc2_devicetype_neo_analog,
// Obsolete
icsneoc2_devicetype_ct_obd,
// neoVI ION
icsneoc2_devicetype_ion,
// RAD-Star - Obsolete
icsneoc2_devicetype_rad_star,
// ValueCAN4-4
icsneoc2_devicetype_vcan44,
// ValueCAN4-2
icsneoc2_devicetype_vcan42,
// CMProbe - Obsolete
icsneoc2_devicetype_cm_probe,
// Ethernet EVB - Obsolete
icsneoc2_devicetype_eevb,
// ValueCAN.rf - Obsolete
icsneoc2_devicetype_vcan_rf,
// neoVI FIRE2
icsneoc2_devicetype_fire2,
// neoVI FLEX - Obsolete
icsneoc2_devicetype_flex,
// RAD-Galaxy
icsneoc2_devicetype_rad_galaxy,
// RAD-Star 2
icsneoc2_devicetype_rad_star2,
// VividCAN
icsneoc2_devicetype_vividcan,
// neoOBD2 SIM
icsneoc2_devicetype_obd2_sim,
// RAD-Galaxy 2
icsneoc2_devicetype_rad_galaxy2,
// Must be last entry
icsneoc2_devicetype_maxsize,
};
auto i = 0;
for (const auto& devicetypeValue : devicetypeValues) {
ASSERT_EQ(devicetypeValue, i++);
}
ASSERT_EQ(sizeof(icsneoc2_devicetype_t), sizeof(uint32_t));
}
TEST(icsneoc2, test_icsneoc2_msg_type_t) {
std::vector<_icsneoc2_msg_type_t> msgtypeValues = {
icsneoc2_msg_type_device,
icsneoc2_msg_type_internal,
icsneoc2_msg_type_bus,
icsneoc2_msg_type_maxsize,
};
auto i = 0;
for (const auto& msgtypeValue : msgtypeValues) {
ASSERT_EQ(msgtypeValue, i++);
}
ASSERT_EQ(sizeof(icsneoc2_msg_type_t), sizeof(uint32_t));
}
TEST(icsneoc2, test_icsneoc2_msg_bus_type_t) {
std::vector<_icsneoc2_msg_bus_type_t> msgbustypeValues = {
icsneoc2_msg_bus_type_invalid,
icsneoc2_msg_bus_type_internal, // Used for statuses that don't actually need to be transferred to the client application
icsneoc2_msg_bus_type_can,
icsneoc2_msg_bus_type_lin,
icsneoc2_msg_bus_type_flexray,
icsneoc2_msg_bus_type_most,
icsneoc2_msg_bus_type_ethernet,
icsneoc2_msg_bus_type_lsftcan,
icsneoc2_msg_bus_type_swcan,
icsneoc2_msg_bus_type_iso9141,
icsneoc2_msg_bus_type_i2c,
icsneoc2_msg_bus_type_a2b,
icsneoc2_msg_bus_type_spi,
icsneoc2_msg_bus_type_mdio,
// Must be last entry
icsneoc2_msg_bus_type_maxsize,
};
auto i = 0;
for (const auto& msgbustypeValue : msgbustypeValues) {
ASSERT_EQ(msgbustypeValue, i++);
}
ASSERT_EQ(sizeof(icsneoc2_msg_bus_type_t), sizeof(uint8_t));
}
TEST(icsneoc2, test_icsneoc2_netid_t) {
std::vector<std::tuple<_icsneoc2_netid_t, icsneoc2_netid_t>> netidValues = {
{ icsneoc2_netid_device, 0 },
{ icsneoc2_netid_hscan, 1 },
{ icsneoc2_netid_mscan, 2 },
{ icsneoc2_netid_swcan, 3 },
{ icsneoc2_netid_lsftcan, 4 },
{ icsneoc2_netid_fordscp, 5 },
{ icsneoc2_netid_j1708, 6 },
{ icsneoc2_netid_aux, 7 },
{ icsneoc2_netid_j1850vpw, 8 },
{ icsneoc2_netid_iso9141, 9 },
{ icsneoc2_netid_disk_data, 10 },
{ icsneoc2_netid_main51, 11 },
{ icsneoc2_netid_red, 12 },
{ icsneoc2_netid_sci, 13 },
{ icsneoc2_netid_iso9141_2, 14 },
{ icsneoc2_netid_iso14230, 15 },
{ icsneoc2_netid_lin, 16 },
{ icsneoc2_netid_op_ethernet1, 17 },
{ icsneoc2_netid_op_ethernet2, 18 },
{ icsneoc2_netid_op_ethernet3, 19 },
{ icsneoc2_netid_red_ext_memoryread, 20 },
{ icsneoc2_netid_red_int_memoryread, 21 },
{ icsneoc2_netid_red_dflash_read, 22 },
{ icsneoc2_netid_neo_memory_sdread, 23 }, // Response from NeoMemory (MemoryTypeSD)
{ icsneoc2_netid_can_errbits, 24 },
{ icsneoc2_netid_neo_memory_write_done, 25 },
{ icsneoc2_netid_red_wave_can1_logical, 26 },
{ icsneoc2_netid_red_wave_can2_logical, 27 },
{ icsneoc2_netid_red_wave_lin1_logical, 28 },
{ icsneoc2_netid_red_wave_lin2_logical, 29 },
{ icsneoc2_netid_red_wave_lin1_analog, 30 },
{ icsneoc2_netid_red_wave_lin2_analog, 31 },
{ icsneoc2_netid_red_wave_misc_analog, 32 },
{ icsneoc2_netid_red_wave_miscdio2_logical, 33 },
{ icsneoc2_netid_red_network_com_enable_ex, 34 },
{ icsneoc2_netid_red_neovi_network, 35 },
{ icsneoc2_netid_red_read_baud_settings, 36 },
{ icsneoc2_netid_red_oldformat, 37 },
{ icsneoc2_netid_red_scope_capture, 38 },
{ icsneoc2_netid_red_hardware_excep, 39 },
{ icsneoc2_netid_red_get_rtc, 40 },
{ icsneoc2_netid_iso9141_3, 41 },
{ icsneoc2_netid_hscan2, 42 },
{ icsneoc2_netid_hscan3, 44 },
{ icsneoc2_netid_op_ethernet4, 45 },
{ icsneoc2_netid_op_ethernet5, 46 },
{ icsneoc2_netid_iso9141_4, 47 },
{ icsneoc2_netid_lin2, 48 },
{ icsneoc2_netid_lin3, 49 },
{ icsneoc2_netid_lin4, 50 },
{ icsneoc2_netid_most_unused, 51 }, // MOST = 51, Old and unused
{ icsneoc2_netid_red_app_error, 52 },
{ icsneoc2_netid_cgi, 53 },
{ icsneoc2_netid_reset_status, 54 },
{ icsneoc2_netid_fb_status, 55 },
{ icsneoc2_netid_app_signal_status, 56 },
{ icsneoc2_netid_read_datalink_cm_tx_msg, 57 },
{ icsneoc2_netid_read_datalink_cm_rx_msg, 58 },
{ icsneoc2_netid_logging_overflow, 59 },
{ icsneoc2_netid_read_settings, 60 },
{ icsneoc2_netid_hscan4, 61 },
{ icsneoc2_netid_hscan5, 62 },
{ icsneoc2_netid_rs232, 63 },
{ icsneoc2_netid_uart, 64 },
{ icsneoc2_netid_uart2, 65 },
{ icsneoc2_netid_uart3, 66 },
{ icsneoc2_netid_uart4, 67 },
{ icsneoc2_netid_swcan2, 68 },
{ icsneoc2_netid_ethernet_daq, 69 },
{ icsneoc2_netid_data_to_host, 70 },
{ icsneoc2_netid_textapi_to_host, 71 },
{ icsneoc2_netid_spi1, 72 },
{ icsneoc2_netid_op_ethernet6, 73 },
{ icsneoc2_netid_red_vbat, 74 },
{ icsneoc2_netid_op_ethernet7, 75 },
{ icsneoc2_netid_op_ethernet8, 76 },
{ icsneoc2_netid_op_ethernet9, 77 },
{ icsneoc2_netid_op_ethernet10, 78 },
{ icsneoc2_netid_op_ethernet11, 79 },
{ icsneoc2_netid_flexray1a, 80 },
{ icsneoc2_netid_flexray1b, 81 },
{ icsneoc2_netid_flexray2a, 82 },
{ icsneoc2_netid_flexray2b, 83 },
{ icsneoc2_netid_lin5, 84 },
{ icsneoc2_netid_flexray, 85 },
{ icsneoc2_netid_flexray2, 86 },
{ icsneoc2_netid_op_ethernet12, 87 },
{ icsneoc2_netid_i2c, 88 },
{ icsneoc2_netid_most25, 90 },
{ icsneoc2_netid_most50, 91 },
{ icsneoc2_netid_most150, 92 },
{ icsneoc2_netid_ethernet, 93 },
{ icsneoc2_netid_gmfsa, 94 },
{ icsneoc2_netid_tcp, 95 },
{ icsneoc2_netid_hscan6, 96 },
{ icsneoc2_netid_hscan7, 97 },
{ icsneoc2_netid_lin6, 98 },
{ icsneoc2_netid_lsftcan2, 99 },
{ icsneoc2_netid_logical_disk_info, 187 },
{ icsneoc2_netid_wivi_command, 221 },
{ icsneoc2_netid_script_status, 224 },
{ icsneoc2_netid_eth_phy_control, 239 },
{ icsneoc2_netid_extended_command, 240 },
{ icsneoc2_netid_extended_data, 242 },
{ icsneoc2_netid_flexray_control, 243 },
{ icsneoc2_netid_coremini_preload, 244 },
{ icsneoc2_netid_hw_com_latency_test, 512 },
{ icsneoc2_netid_device_status, 513 },
{ icsneoc2_netid_udp, 514 },
{ icsneoc2_netid_forwarded_message, 516 },
{ icsneoc2_netid_i2c2, 517 },
{ icsneoc2_netid_i2c3, 518 },
{ icsneoc2_netid_i2c4, 519 },
{ icsneoc2_netid_ethernet2, 520 },
{ icsneoc2_netid_a2b1, 522 },
{ icsneoc2_netid_a2b2, 523 },
{ icsneoc2_netid_ethernet3, 524 },
{ icsneoc2_netid_wbms, 532 },
{ icsneoc2_netid_dwcan9, 534 },
{ icsneoc2_netid_dwcan10, 535 },
{ icsneoc2_netid_dwcan11, 536 },
{ icsneoc2_netid_dwcan12, 537 },
{ icsneoc2_netid_dwcan13, 538 },
{ icsneoc2_netid_dwcan14, 539 },
{ icsneoc2_netid_dwcan15, 540 },
{ icsneoc2_netid_dwcan16, 541 },
{ icsneoc2_netid_lin7, 542 },
{ icsneoc2_netid_lin8, 543 },
{ icsneoc2_netid_spi2, 544 },
{ icsneoc2_netid_mdio1, 545 },
{ icsneoc2_netid_mdio2, 546 },
{ icsneoc2_netid_mdio3, 547 },
{ icsneoc2_netid_mdio4, 548 },
{ icsneoc2_netid_mdio5, 549 },
{ icsneoc2_netid_mdio6, 550 },
{ icsneoc2_netid_mdio7, 551 },
{ icsneoc2_netid_mdio8, 552 },
{ icsneoc2_netid_op_ethernet13, 553 },
{ icsneoc2_netid_op_ethernet14, 554 },
{ icsneoc2_netid_op_ethernet15, 555 },
{ icsneoc2_netid_op_ethernet16, 556 },
{ icsneoc2_netid_spi3, 557 },
{ icsneoc2_netid_spi4, 558 },
{ icsneoc2_netid_spi5, 559 },
{ icsneoc2_netid_spi6, 560 },
{ icsneoc2_netid_spi7, 561 },
{ icsneoc2_netid_spi8, 562 },
{ icsneoc2_netid_lin9, 563 },
{ icsneoc2_netid_lin10, 564 },
{ icsneoc2_netid_lin11, 565 },
{ icsneoc2_netid_lin12, 566 },
{ icsneoc2_netid_lin13, 567 },
{ icsneoc2_netid_lin14, 568 },
{ icsneoc2_netid_lin15, 569 },
{ icsneoc2_netid_lin16, 570 },
{ icsneoc2_netid_maxsize, 571 }
};
for (const auto& netidValue : netidValues) {
const _icsneoc2_netid_t actualValue = std::get<0>(netidValue);
const icsneoc2_netid_t expectedValue = std::get<1>(netidValue);
ASSERT_EQ(actualValue, expectedValue);
}
}