Author SHA1 Message Date
Paul Hollinsky f16ee630ee Checksum failure logging to stderr for debugging 2019-11-06 10:24:55 -05:00
Paul Hollinsky f0582697a6 Clarify FlexRay Slot ID 2019-11-01 14:48:14 -04:00
Jeffrey Quesnelle b990e03343 add CMake options to disable certain targets and fix a few compiler warnings 2019-10-17 09:43:50 -04:00
Jeffrey Quesnelle 423f854682 fix MSVC build errors and warnings 2019-10-16 23:56:49 -04:00
Paul Hollinsky eb856dffec Quiet down warnings on Windows 2019-10-16 17:43:11 -04:00
Paul Hollinsky debaf8f0cb Merge branch 'v0.2.0-dev' of github.com:intrepidcs/libicsneo into v0.2.0-dev 2019-10-16 16:44:16 -04:00
Paul Hollinsky 2f9844df92 Begin work on FlexRay support 2019-10-16 16:43:31 -04:00
Paul Hollinsky 5795efbde8 Merge changes from v0.1.2
Dropping the updateLEDState fix as the one on this branch is nicer
2019-09-04 13:40:42 -04:00
Paul Hollinsky 0607986114 Resolve merge conflicts 2019-08-12 11:17:28 -04:00
EricLiu2000 ef16e60025 Added more mutexes in eventmanager, fixed exiting destruction bug 2019-08-07 13:12:16 -04:00
EricLiu2000 9629864f1b Fixed wait check in device online/offline 2019-08-07 10:06:33 -04:00
Jeffrey Quesnelle 781b23c0e7 std::chrono::seconds::duration should just be std::chrono::seconds 2019-08-06 17:35:44 -04:00
Jeffrey Quesnelle 5112e1d2f9 fix building for macos 2019-08-06 17:14:12 -04:00
EricLiu2000 3358241abe Reordered error downgrading, order of going offline, and renamed locks 2019-08-06 10:32:19 -04:00
EricLiu2000 01c62b6445 Replaced formal parameter filter in addmessagecallback and addeventcallback 2019-08-06 10:31:08 -04:00
EricLiu2000 4a81b9443a Changed getpollingmessagelimit to return an int 2019-08-05 17:25:09 -04:00
EricLiu2000 71176137ca Added waits to ensure going online and offline succeed before returning 2019-08-05 15:35:44 -04:00
EricLiu2000 451f0a9ac1 Added documentation for event callbacks 2019-08-05 11:41:01 -04:00
EricLiu2000 1aeee082ae Testing successful removal of events from within event callbacks 2019-08-05 11:40:47 -04:00
EricLiu2000 9b3d36c8c1 Moved calling of event callbacks to after the event is added. Now using unique_locks on the list of events to allow event callbacks to safely modify the list of events 2019-08-05 11:40:17 -04:00
EricLiu2000 bf77b7ac3b Added event callbacks multithreaded test and added documentation 2019-08-05 10:57:48 -04:00
EricLiu2000 2108d6223c Fixed runtime error casting placeholder void* to void in message and event callbacks 2019-08-05 10:32:23 -04:00
EricLiu2000 9040edc25d Added event callback functionality in icsneoc 2019-08-02 16:32:15 -04:00
EricLiu2000 4f735a651c Added event callback functionality. EventManager now uses multiple mutexes to lock events, errors, callbacks, and downgradedThreads separately. Wrote single-threaded test for event callbacks. 2019-08-02 15:00:31 -04:00
EricLiu2000 f9712a4bcd Added error flag when packetizer and multichannelcommunication fail to read 2019-08-01 16:21:29 -04:00
EricLiu2000 453f098cdb Added check to see if message polling is enabled before disabling it in device destructor 2019-08-01 14:08:12 -04:00
EricLiu2000 f41b5c4a79 Removed cancellation of error downgrading after closing, was causing read access violations. 2019-08-01 14:07:42 -04:00
EricLiu2000 055cae1232 Removed radpluto override of setupDecoder() in order to fix timestamp 2019-08-01 13:40:38 -04:00
EricLiu2000 8516a9c8bd Added placeholder void* filter parameter to icsneo_addMessageCallback and added more documentation for message callback functions 2019-07-30 14:02:34 -04:00
EricLiu2000 655a483aee Cleaned up icsneolegacy returns that use icsneo_settingsReadStructure 2019-07-30 10:29:42 -04:00
EricLiu2000 c10224002a Added message callback functionality in c and canceled error downgrading on user callbacks in communication as well 2019-07-30 10:22:27 -04:00
EricLiu2000 5a98bac8a6 Standardized int-returning functions in icsneoc library to return -1 on failure. Updated icsneolegacy accordingly, and added headers for message callback functionality in c 2019-07-29 16:08:54 -04:00
EricLiu2000 54b98ec9b4 Error downgrading now uses a map<threadid, bool>, and error downgrading is canceled during message callbacks 2019-07-29 15:16:35 -04:00
EricLiu2000 ff1e65b292 Added flag BUILD_DOCS for documentation in CMakeLists.txt 2019-07-29 14:30:50 -04:00
EricLiu2000 f1632aada5 Added overview section for API concepts and added more detailed explanation of message callbacks and polling 2019-07-29 12:57:00 -04:00
EricLiu2000 c62ea4d05f Ignoring _build 2019-07-29 12:57:00 -04:00
Paul Hollinsky 511a724252 POSIX FTDI: Improve performance by setting the latency timer 2019-07-26 17:46:24 -04:00
EricLiu2000 f30b2ef11c Added official documentation for device concepts in usage 2019-07-26 15:12:17 -04:00
EricLiu2000 f009d8cac5 Wrote official documentation for the events and error system 2019-07-26 13:34:35 -04:00
EricLiu2000 b75536c4a2 Updated some documentation in eventmanager to reflect chronological pruning of events 2019-07-26 13:34:03 -04:00
EricLiu2000 4654742046 Updated copyrights from 2018 to 2019 2019-07-25 16:49:07 -04:00
EricLiu2000 80999251ef Updated library version numbers to 0.2.0 2019-07-25 16:45:54 -04:00
EricLiu2000 16205d29b6 Added initial documentation files for c#, java, and usage 2019-07-25 16:43:33 -04:00
EricLiu2000 8c186f00cd Added functionality to set blocking behavior of write 2019-07-24 14:57:06 -04:00
EricLiu2000 69b7e5b45a Device::GetMessages now returns a pair of {vector, bool} instead of vector 2019-07-24 13:40:54 -04:00
EricLiu2000 66126b2b61 Downgraded non-user thread errors to warnings 2019-07-24 13:22:17 -04:00
EricLiu2000 6f8d307850 Implemented thread specific error-downgrading to events and wrote corresponding unit test 2019-07-24 12:52:15 -04:00
EricLiu2000 42a5d525ce Renamed test suite in CMakeLists.txt 2019-07-23 17:20:25 -04:00
EricLiu2000 199bd2b144 Reverted refactor changes to icsneolegacy.h 2019-07-23 17:16:27 -04:00
Paul Hollinsky 21c3fead4a Error checking for Encoder::encode UpdateLEDState 2019-07-23 15:04:50 -04:00
Paul Hollinsky 77eed8f58d Revise documentation for icsneo_getLastError 2019-07-23 15:03:43 -04:00
EricLiu2000 69a7b9bc2d Removed casts in network.h constants for SWIG compatibility 2019-07-17 16:36:40 -04:00
EricLiu2000 65cd6ff8c8 Cleaned up some formatting 2019-07-17 15:22:13 -04:00
EricLiu2000 42690d1f9a Updated documentation, added multithreaded test with both events and errors for eventmanager 2019-06-28 11:11:58 -04:00
EricLiu2000 e3517767cb Events are now removed purely in chronological order if overflowing 2019-06-27 18:04:59 -04:00
EricLiu2000 70d5b4f5b5 Reordered tests 2019-06-27 17:28:54 -04:00
EricLiu2000 a4ddd24a50 Added functionality for filtering by both type and severity. Wrote tests for eventmanager::get 2019-06-27 17:04:07 -04:00
EricLiu2000 baa9404432 Went back to normal mutex because I forgot I reverted those 2019-06-27 16:02:31 -04:00
EricLiu2000 1d3b3359ca Wrote more tests, fixed bug with eventmanager::get(size), optimized eventmanager adding and shrinking, prevented trying to add TooManyEvents 2019-06-27 15:50:22 -04:00
EricLiu2000 d0c6aba0fc Revert "Changed list of events to vector, switched back to using lock_guard instead of shared/unique_locks"
This reverts commit 2dac03b3e5.
2019-06-27 14:16:36 -04:00
EricLiu2000 2dac03b3e5 Changed list of events to vector, switched back to using lock_guard instead of shared/unique_locks 2019-06-27 13:42:02 -04:00
EricLiu2000 a9a2a978b8 Fixed multithreading issue with eventmanager 2019-06-27 13:20:13 -04:00
EricLiu2000 ec95f0f7c3 Wrote more tests and fixed locking bug in eventmanager 2019-06-26 15:08:41 -04:00
EricLiu2000 975c7f422f CMake properly uses -DBUILD_TESTS flag, added CmakeSettings.json to gitignore 2019-06-26 11:53:06 -04:00
EricLiu2000 4923218d35 Separated tests into different files, added ResetInstance() method to EventManager 2019-06-26 11:30:24 -04:00
EricLiu2000 1dd68eb0d0 Test framework tentatively working on windows 2019-06-25 18:01:32 -04:00
EricLiu2000 bb2d7c1265 Reversed nullptr device check 2019-06-25 17:46:59 -04:00
EricLiu2000 150c7d2b07 Added gtest folder and building doesn't throw errors 2019-06-25 16:56:04 -04:00
EricLiu2000 f45bd6772f Builds and runs on both windows and ubuntu 2019-06-25 13:20:49 -04:00
EricLiu2000 92dc23fa4b Updated README for refactor 2019-06-25 12:48:58 -04:00
EricLiu2000 2f971d7565 Runs on windows 2019-06-25 11:35:40 -04:00
EricLiu2000 50dba62a89 Event refactor builds on Windows 2019-06-24 17:59:45 -04:00
EricLiu2000 878d9e6dde Implemented threaded error handling in errormanager and fixed compile error 2019-06-21 16:14:52 -04:00
EricLiu2000 f9d88b4743 Upgraded the severity of some warnings to errors and cleaned up internal API error adding 2019-06-21 15:08:08 -04:00
EricLiu2000 cb6f88c6bb Initial rework of internal management for overflowing errors 2019-06-21 11:18:24 -04:00
EricLiu2000 33ad0c1967 C++ error descriptions now distinguish between severity levels 2019-06-19 11:00:41 -04:00
EricLiu2000 12cb4c227a icsneolegacy icsneoOpenNeoDevice return now checks success for setting polling message limit and enabling message polling too 2019-06-18 11:40:18 -04:00
EricLiu2000 92368f70a5 Added error checking for polling 2019-06-18 11:38:12 -04:00
EricLiu2000 2b34c82382 Added error checking to Device::getMessages() 2019-06-18 10:34:50 -04:00
EricLiu2000 04a2402925 Added additional documentation 2019-06-14 17:44:01 -04:00
EricLiu2000 a4a42c8704 Reworked updating LEDState to use sendCommand() instead of transmit() 2019-06-14 16:09:19 -04:00
EricLiu2000 28fc98c475 Added icsneo_isMessagePollingEnabled(), removed polling check from transmitting, and disabled error reporting on device destruction 2019-06-14 15:13:22 -04:00
Paul HollinskyandEricLiu2000 a608d21304 Fix for error at pcap and vcp level on Windows causes crash 2019-06-14 09:41:47 -04:00
EricLiu2000 44ca4d4db1 Removed extraneous error checking 2019-06-13 16:04:20 -04:00
EricLiu2000 b7288edd9a Finished adding error checking 2019-06-13 16:01:35 -04:00
EricLiu2000 255e1e2b90 Added more error logging 2019-06-13 16:01:35 -04:00
EricLiu2000 dc4f96affb Commands can now only be sent when the device is open 2019-06-13 16:01:35 -04:00
EricLiu2000 8a6073a9cf Transmit and receiving messages now fails properly when the device is closed. Device closes when serial number initialization fails after open. 2019-06-13 16:01:35 -04:00
EricLiu2000 519e64fb17 Added error checking to functions called from Communication 2019-06-13 16:01:35 -04:00
EricLiu2000 a16f2843d8 Added error reporting to idevicesettings 2019-06-13 16:01:35 -04:00
EricLiu2000 965679c370 Added error checking and removed some redundancy from device isOpen() 2019-06-13 16:01:35 -04:00
EricLiu2000 2806c935f1 Added errors for DeviceCurrentlyOpen and DeviceCurrentlyClosed 2019-06-13 16:01:35 -04:00
EricLiu2000 8862a06c3d Added .vs to gitignore 2019-06-13 16:01:35 -04:00
EricLiu2000 903615dadd Added icsneo_isOpen() functionality 2019-06-13 16:01:35 -04:00
EricLiu2000 f1e0625429 Fixed typo in documentation of icsneo_getLastError 2019-06-13 16:01:35 -04:00
EricLiu2000 0644234859 Removed hard coded .dll filepaths 2019-06-13 16:01:35 -04:00
EricLiu2000 9b21c153c7 Fixed icsneoc.h to work with c 2019-06-13 16:01:35 -04:00
Paul Hollinsky b7dbeccaef Lock before adding or removing message callbacks 2019-06-13 15:47:23 -04:00
376 changed files with 121132 additions and 1362 deletions
+2
View File
@@ -1,7 +1,9 @@
_build/
build/
build*/
.DS_Store
Thumbs.db
CMakeSettings.json
.vscode
third-party/concurrentqueue/benchmarks
third-party/concurrentqueue/tests
+121 -84
View File
@@ -1,5 +1,11 @@
cmake_minimum_required(VERSION 3.2)
project(libicsneo VERSION 0.1.2)
project(libicsneo VERSION 0.2.0)
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
option(LIBICSNEO_BUILD_ICSNEOC "Build dynamic C library" ON)
option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
set(CMAKE_CXX_STANDARD 11)
@@ -7,11 +13,6 @@ include(GNUInstallDirs)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# macOS Homebrew Boost Fix
if(NOT MSVC)
include_directories(AFTER /usr/local/include)
endif()
# Enable Warnings
if(MSVC)
# Force to always compile with W4
@@ -21,62 +22,65 @@ if(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-nested-anon-types -Wno-gnu-anonymous-struct -Wno-unknown-pragmas -Wno-zero-length-array")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
endif()
# doxygen
find_package(Doxygen)
if(DOXYGEN_FOUND)
set(DOXYGEN_OUT ${CMAKE_CURRENT_SOURCE_DIR}/generated/Doxyfile)
set(DOXYGEN_OUT ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile)
set(ICSNEO_DOCS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/docs)
if(NOT EXISTS "${DOXYGEN_OUT}")
set(DOXYGEN_FOUND FALSE)
endif()
endif()
if(DOXYGEN_FOUND)
message("Will build Doxygen based documentation")
if(LIBICSNEO_BUILD_DOCS)
if(DOXYGEN_FOUND)
message("Will build Doxygen based documentation")
add_custom_target(libicsneo_doxygen ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM
DEPENDS icsneocpp icsneoc icsneolegacy)
# sphinx
find_package(Sphinx)
if(SPHINX_EXECUTABLE)
message("Will build Sphinx based documentation")
set(SPHINX_OUT ${ICSNEO_DOCS_DIR}/build/sphinx)
# configured documentation tools and intermediate build results
set(SPHINX_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_build)
# Sphinx cache with pickled ReST documents
set(SPHINX_CACHE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_doctrees)
# HTML output directory
set(SPHINX_HTML_DIR ${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx)
configure_file(
"${ICSNEO_DOCS_DIR}/conf.py.template"
"${ICSNEO_DOCS_DIR}/conf.py"
@ONLY)
add_custom_target(libicsneo_sphinx ALL
${SPHINX_EXECUTABLE}
-q -b html
-c "${ICSNEO_DOCS_DIR}"
-d "${SPHINX_CACHE_DIR}"
"${ICSNEO_DOCS_DIR}"
"${SPHINX_HTML_DIR}"
COMMENT "Building HTML documentation with Sphinx"
add_custom_target(libicsneo_doxygen ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM
DEPENDS icsneocpp icsneoc icsneolegacy)
# sphinx
find_package(Sphinx)
if(SPHINX_EXECUTABLE)
message("Will build Sphinx based documentation")
set(SPHINX_OUT ${ICSNEO_DOCS_DIR}/build/sphinx)
# configured documentation tools and intermediate build results
set(SPHINX_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/_build)
# Sphinx cache with pickled ReST documents
set(SPHINX_CACHE_DIR ${CMAKE_CURRENT_BINARY_DIR}/_doctrees)
# HTML output directory
set(SPHINX_HTML_DIR ${CMAKE_CURRENT_BINARY_DIR}/doc_sphinx)
configure_file(
"${ICSNEO_DOCS_DIR}/conf.py.template"
"${ICSNEO_DOCS_DIR}/conf.py"
@ONLY)
add_custom_target(libicsneo_sphinx
${SPHINX_EXECUTABLE}
-q -b html
-c "${ICSNEO_DOCS_DIR}"
-d "${SPHINX_CACHE_DIR}"
"${ICSNEO_DOCS_DIR}"
"${SPHINX_HTML_DIR}"
COMMENT "Building HTML documentation with Sphinx"
DEPENDS icsneocpp icsneoc icsneolegacy)
endif()
endif()
endif()
if(WIN32)
file(GLOB PLATFORM_SRC_EXTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/*.cpp)
file(GLOB PLATFORM_SRC_INTERNAL ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/internal/*.cpp)
@@ -86,7 +90,9 @@ else()
endif()
set(COMMON_SRC
communication/message/flexray/control/flexraycontrolmessage.cpp
communication/message/neomessage.cpp
communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp
communication/packet/ethernetpacket.cpp
communication/decoder.cpp
@@ -95,6 +101,8 @@ set(COMMON_SRC
communication/multichannelcommunication.cpp
communication/communication.cpp
communication/icommunication.cpp
device/extensions/flexray/extension.cpp
device/extensions/flexray/controller.cpp
device/idevicesettings.cpp
device/devicefinder.cpp
device/device.cpp
@@ -133,8 +141,8 @@ include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
add_library(icsneocpp
api/icsneocpp/icsneocpp.cpp
api/icsneocpp/error.cpp
api/icsneocpp/errormanager.cpp
api/icsneocpp/event.cpp
api/icsneocpp/eventmanager.cpp
api/icsneocpp/version.cpp
${SRC_FILES}
)
@@ -146,6 +154,7 @@ target_include_directories(icsneocpp
${CMAKE_CURRENT_SOURCE_DIR}/include
)
set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
# libftdi
if(NOT WIN32)
@@ -166,44 +175,48 @@ if(WIN32)
add_definitions(-DWPCAP -DHAVE_REMOTE -DWIN32_LEAN_AND_MEAN)
endif(WIN32)
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
target_include_directories(icsneoc
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc PRIVATE icsneocpp)
if(LIBICSNEO_BUILD_ICSNEOC)
add_library(icsneoc SHARED api/icsneoc/icsneoc.cpp ${CMAKE_CURRENT_BINARY_DIR}/generated/icsneoc/version.rc)
target_include_directories(icsneoc
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc PRIVATE icsneocpp)
target_compile_features(icsneoc PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
add_library(icsneoc-static STATIC api/icsneoc/icsneoc.cpp)
target_include_directories(icsneoc-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
add_library(icsneoc-static STATIC api/icsneoc/icsneoc.cpp)
target_include_directories(icsneoc-static
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneoc-static PUBLIC icsneocpp)
target_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
)
target_include_directories(icsneolegacy
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneolegacy PRIVATE icsneocpp)
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_features(icsneoc PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_features(icsneoc-static PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
target_compile_features(icsneolegacy PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
if(LIBICSNEO_BUILD_ICSNEOLEGACY)
add_library(icsneolegacy SHARED
api/icsneolegacy/icsneolegacy.cpp
api/icsneolegacy/icsneolegacyextra.cpp
api/icsneoc/icsneoc.cpp
)
target_include_directories(icsneolegacy
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(icsneolegacy PRIVATE icsneocpp)
target_compile_features(icsneolegacy PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
endif()
# libftdi
if(NOT WIN32)
@@ -215,6 +228,30 @@ if(NOT WIN32)
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
endif()
# googletest
if(LIBICSNEO_BUILD_TESTS)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
add_subdirectory(third-party/googletest-master)
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
add_executable(runTests test/main.cpp test/eventmanagertest.cpp)
target_link_libraries(runTests gtest gtest_main)
target_link_libraries(runTests icsneocpp)
target_include_directories(runTests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
enable_testing()
add_test(NAME testSuite COMMAND runTests)
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2018-2019 Intrepid Control Systems, Inc.
Copyright 2019-2020 Intrepid Control Systems, Inc.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+8 -8
View File
@@ -1,5 +1,5 @@
# libicsneo
### The Intrepid Control Systems Open Cross-Platform Device Communication API
### The Intrepid Control Systems Open Source Cross-Platform Device Communication API
An open source solution to integrate Intrepid Control Systems vehicle networking hardware with your application.
@@ -38,11 +38,10 @@ std::cout << devices.size() << " found!" << std::endl;
for(auto& device : devices)
std::cout << "Found " << device->describe() << std::endl; // "Found neoVI FIRE 2 CY2345"
std::shared_ptr<icsneo::Device> myDevice = devices[0];
if(!myDevice->open()) {
// There was an error while attempting to open the device, print the error details
for(auto& error : icsneo::getErrors())
std::cout << error << std::endl;
}
if(!myDevice->open()) // Device tried and failed to open, print the last error
std::cout << icsneo::GetLastError() << std::endl;
myDevice->goOnline(); // Start receiving messages
myDevice->enableMessagePolling(); // Allow the use of myDevice->getMessages() later
// Alternatively, assign a callback for new messages
@@ -88,7 +87,7 @@ for(size_t i = 0; i < deviceCount; i++) {
neodevice_t* myDevice = &devices[0];
if(!icsneo_openDevice(myDevice)) {
neoerror_t error;
neoevent_t error;
if(icsneo_getLastError(&error))
printf("Error! %s\n", error.description);
}
@@ -113,7 +112,7 @@ icsneo_closeDevice(myDevice);
## Building from Source
### Windows
Building will require Microsoft Visual Studio 2017 and CMake to be installed.
Building will require Microsoft Visual Studio 2017+ and CMake to be installed.
### macOS
Getting the dependencies is easiest with the Homebrew package manager. You will also need XCode installed. You can then install CMake, an up-to-date version of GCC or Clang, and `libusb-1.0`.
### Linux
@@ -121,6 +120,7 @@ The dependencies are as follows
- CMake 3.2 or above
- GCC 4.7 or above, 4.8+ recommended
- `libusb-1.0-0-dev`
- `libpcap0.8-dev`
- `build-essential` is recommended
If you'd like to be able to run programs that use this library without being root, consider using the included udev rules
+148 -142
View File
@@ -7,9 +7,10 @@
#include "icsneo/icsneoc.h"
#include "icsneo/icsneocpp.h"
#include "icsneo/platform/dynamiclib.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/device/devicefinder.h"
#include <string>
#include <functional>
#include <vector>
#include <memory>
#include <algorithm>
@@ -28,7 +29,7 @@ void icsneo_findAllDevices(neodevice_t* devices, size_t* count) {
std::vector<std::shared_ptr<Device>> foundDevices = icsneo::FindAllDevices();
if(count == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return;
}
@@ -43,7 +44,7 @@ void icsneo_findAllDevices(neodevice_t* devices, size_t* count) {
*count = foundDevices.size();
size_t outputSize = *count;
if(outputSize > inputSize) {
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
outputSize = inputSize;
}
@@ -60,7 +61,7 @@ void icsneo_freeUnconnectedDevices() {
bool icsneo_serialNumToString(uint32_t num, char* str, size_t* count) {
// TAG String copy function
if(count == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
@@ -73,7 +74,7 @@ bool icsneo_serialNumToString(uint32_t num, char* str, size_t* count) {
if(*count < result.length()) {
*count = result.length() + 1; // This is how big of a buffer we need
ErrorManager::GetInstance().add(APIError::BufferInsufficient);
EventManager::GetInstance().add(APIEvent::Type::BufferInsufficient, APIEvent::Severity::Error);
return false;
}
@@ -87,6 +88,11 @@ uint32_t icsneo_serialStringToNum(const char* str) {
}
bool icsneo_isValidNeoDevice(const neodevice_t* device) {
// return false on nullptr
if(!device) {
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
// If this neodevice_t was returned by a previous search, it will no longer be valid (as the underlying icsneo::Device is freed)
for(auto& dev : connectedDevices) {
if(dev.get() == device->device)
@@ -96,14 +102,14 @@ bool icsneo_isValidNeoDevice(const neodevice_t* device) {
if(dev.get() == device->device)
return true;
}
EventManager::GetInstance().add(APIEvent::Type::InvalidNeoDevice, APIEvent::Severity::Error);
return false;
}
bool icsneo_openDevice(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
if(!device->device->open())
return false;
@@ -123,10 +129,8 @@ bool icsneo_openDevice(const neodevice_t* device) {
}
bool icsneo_closeDevice(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
if(!device->device->close())
return false;
@@ -143,60 +147,61 @@ bool icsneo_closeDevice(const neodevice_t* device) {
return true;
}
bool icsneo_isOpen(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->isOpen();
}
bool icsneo_goOnline(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->goOnline();
}
bool icsneo_goOffline(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->goOffline();
}
bool icsneo_isOnline(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->isOnline();
}
bool icsneo_enableMessagePolling(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
device->device->enableMessagePolling();
return true;
return device->device->enableMessagePolling();
}
bool icsneo_disableMessagePolling(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->disableMessagePolling();
}
bool icsneo_isMessagePollingEnabled(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->isMessagePollingEnabled();
}
bool icsneo_getMessages(const neodevice_t* device, neomessage_t* messages, size_t* items, uint64_t timeout) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
if(items == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
@@ -223,36 +228,49 @@ bool icsneo_getMessages(const neodevice_t* device, neomessage_t* messages, size_
return true;
}
size_t icsneo_getPollingMessageLimit(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
return 0;
}
int icsneo_getPollingMessageLimit(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device))
return -1;
return device->device->getPollingMessageLimit();
return (int)device->device->getPollingMessageLimit();
}
bool icsneo_setPollingMessageLimit(const neodevice_t* device, size_t newLimit) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
device->device->setPollingMessageLimit(newLimit);
return true;
}
int icsneo_addMessageCallback(const neodevice_t* device, void (*callback)(neomessage_t), void*) {
if(!icsneo_isValidNeoDevice(device))
return -1;
return device->device->addMessageCallback(
MessageCallback(
[=](std::shared_ptr<icsneo::Message> msg) {
return callback(CreateNeoMessage(msg));
}
)
);
}
bool icsneo_removeMessageCallback(const neodevice_t* device, int id) {
if(!icsneo_isValidNeoDevice(device))
return false;
return device->device->removeMessageCallback(id);
}
bool icsneo_getProductName(const neodevice_t* device, char* str, size_t* maxLength) {
// TAG String copy function
if(maxLength == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
std::string output = device->device->getType().toString();
@@ -265,7 +283,7 @@ bool icsneo_getProductName(const neodevice_t* device, char* str, size_t* maxLeng
str[*maxLength] = '\0';
if(output.length() > *maxLength)
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
return true;
}
@@ -273,7 +291,7 @@ bool icsneo_getProductName(const neodevice_t* device, char* str, size_t* maxLeng
bool icsneo_getProductNameForType(devicetype_t type, char* str, size_t* maxLength) {
// TAG String copy function
if(maxLength == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
@@ -288,76 +306,64 @@ bool icsneo_getProductNameForType(devicetype_t type, char* str, size_t* maxLengt
str[*maxLength] = '\0';
if(output.length() > *maxLength)
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
return true;
}
bool icsneo_settingsRefresh(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->refresh();
}
bool icsneo_settingsApply(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->apply();
}
bool icsneo_settingsApplyTemporary(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->apply(true);
}
bool icsneo_settingsApplyDefaults(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->applyDefaults();
}
bool icsneo_settingsApplyDefaultsTemporary(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->applyDefaults(true);
}
size_t icsneo_settingsReadStructure(const neodevice_t* device, void* structure, size_t structureSize) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
return 0;
}
int icsneo_settingsReadStructure(const neodevice_t* device, void* structure, size_t structureSize) {
if(!icsneo_isValidNeoDevice(device))
return -1;
size_t readSize = device->device->settings->getSize();
if(structure == nullptr) // Structure size request
return readSize;
return (int)readSize;
if(readSize > structureSize) {
// Client application has a smaller structure than we do
// It is probably built against an older version of the API
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
readSize = structureSize;
}
const void* deviceStructure = device->device->settings->getRawStructurePointer();
if(deviceStructure == nullptr) {
ErrorManager::GetInstance().add(APIError::SettingsNotAvailable);
return 0;
EventManager::GetInstance().add(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
memcpy(structure, deviceStructure, readSize);
@@ -365,30 +371,28 @@ size_t icsneo_settingsReadStructure(const neodevice_t* device, void* structure,
if(readSize < structureSize) // Client application is attempting to read more than we have
memset((uint8_t*)structure + readSize, 0, structureSize - readSize);
return readSize;
return (int)readSize;
}
// Not exported
static bool icsneo_settingsWriteStructure(const neodevice_t* device, const void* structure, size_t structureSize) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
if(structure == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
size_t writeSize = device->device->settings->getSize();
if(writeSize < structureSize) {
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
structureSize = writeSize;
}
void* deviceStructure = device->device->settings->getMutableRawStructurePointer();
if(deviceStructure == nullptr) {
ErrorManager::GetInstance().add(APIError::SettingsNotAvailable);
EventManager::GetInstance().add(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
@@ -409,46 +413,36 @@ bool icsneo_settingsApplyStructureTemporary(const neodevice_t* device, const voi
}
int64_t icsneo_getBaudrate(const neodevice_t* device, uint16_t netid) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return -1;
}
return device->device->settings->getBaudrateFor(netid);
}
bool icsneo_setBaudrate(const neodevice_t* device, uint16_t netid, int64_t newBaudrate) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->setBaudrateFor(netid, newBaudrate);
}
int64_t icsneo_getFDBaudrate(const neodevice_t* device, uint16_t netid) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return -1;
}
return device->device->settings->getFDBaudrateFor(netid);
}
bool icsneo_setFDBaudrate(const neodevice_t* device, uint16_t netid, int64_t newBaudrate) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->settings->setFDBaudrateFor(netid, newBaudrate);
}
bool icsneo_transmit(const neodevice_t* device, const neomessage_t* message) {
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
return device->device->transmit(CreateMessageFromNeoMessage(message));
}
@@ -463,17 +457,22 @@ bool icsneo_transmitMessages(const neodevice_t* device, const neomessage_t* mess
return true;
}
void icsneo_setWriteBlocks(const neodevice_t* device, bool blocks) {
if(!icsneo_isValidNeoDevice(device))
return;
device->device->setWriteBlocks(blocks);
}
bool icsneo_describeDevice(const neodevice_t* device, char* str, size_t* maxLength) {
// TAG String copy function
if(maxLength == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
if(!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
if(!icsneo_isValidNeoDevice(device))
return false;
}
std::string output = device->device->describe();
@@ -481,7 +480,7 @@ bool icsneo_describeDevice(const neodevice_t* device, char* str, size_t* maxLeng
str[*maxLength] = '\0';
if(output.length() > *maxLength)
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
return true;
}
@@ -490,92 +489,102 @@ neoversion_t icsneo_getVersion(void) {
return icsneo::GetVersion();
}
bool icsneo_getErrors(neoerror_t* errors, size_t* size) {
int icsneo_addEventCallback(void (*callback)(neoevent_t), void*) {
return EventManager::GetInstance().addEventCallback(
EventCallback(
[=](std::shared_ptr<icsneo::APIEvent> evt) {
return callback(*(evt->getNeoEvent()));
}
)
);
}
bool icsneo_removeEventCallback(int id) {
return EventManager::GetInstance().removeEventCallback(id);
}
bool icsneo_getEvents(neoevent_t* events, size_t* size) {
if(size == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
if(errors == nullptr) {
*size = icsneo::ErrorCount();
if(events == nullptr) {
*size = icsneo::EventCount();
return false;
}
auto cppErrors = icsneo::GetErrors(*size);
auto cppErrors = icsneo::GetEvents(*size);
for(size_t i = 0; i < cppErrors.size(); i++)
memcpy(&errors[i], cppErrors[i].getNeoError(), sizeof(neoerror_t));
memcpy(&events[i], cppErrors[i].getNeoEvent(), sizeof(neoevent_t));
*size = cppErrors.size();
return true;
}
bool icsneo_getDeviceErrors(const neodevice_t* device, neoerror_t* errors, size_t* size) {
if(device != nullptr && !icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
bool icsneo_getDeviceEvents(const neodevice_t* device, neoevent_t* events, size_t* size) {
if(!icsneo_isValidNeoDevice(device))
return false;
}
if(size == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
// Creating the filter will nullptr is okay! It will find any errors not associated with a device.
ErrorFilter filter = (device != nullptr ? device->device : nullptr);
// Creating the filter will nullptr is okay! It will find any events not associated with a device.
EventFilter filter = (device != nullptr ? device->device : nullptr);
if(errors == nullptr) {
*size = icsneo::ErrorCount(filter);
if(events == nullptr) {
*size = icsneo::EventCount(filter);
return false;
}
auto cppErrors = icsneo::GetErrors(*size, filter);
auto cppErrors = icsneo::GetEvents(*size, filter);
for(size_t i = 0; i < cppErrors.size(); i++)
memcpy(&errors[i], cppErrors[i].getNeoError(), sizeof(neoerror_t));
memcpy(&events[i], cppErrors[i].getNeoEvent(), sizeof(neoevent_t));
*size = cppErrors.size();
return true;
}
bool icsneo_getLastError(neoerror_t* error) {
bool icsneo_getLastError(neoevent_t* error) {
if(error == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
APIError cppErr;
if(!icsneo::GetLastError(cppErr))
APIEvent cppErr = icsneo::GetLastError();
if(cppErr.getType() == icsneo::APIEvent::Type::NoErrorFound)
return false;
memcpy(error, cppErr.getNeoError(), sizeof(neoerror_t));
memcpy(error, cppErr.getNeoEvent(), sizeof(neoevent_t));
return true;
}
void icsneo_discardAllErrors(void) {
icsneo::DiscardErrors();
void icsneo_discardAllEvents(void) {
icsneo::DiscardEvents();
}
void icsneo_discardDeviceErrors(const neodevice_t* device) {
if(device != nullptr && !icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
void icsneo_discardDeviceEvents(const neodevice_t* device) {
if(!icsneo_isValidNeoDevice(device))
return;
}
if(device == nullptr)
icsneo::DiscardErrors(nullptr); // Discard errors not associated with a device
icsneo::DiscardEvents(nullptr); // Discard events not associated with a device
else
icsneo::DiscardErrors(device->device);
icsneo::DiscardEvents(device->device);
}
void icsneo_setErrorLimit(size_t newLimit) {
icsneo::SetErrorLimit(newLimit);
void icsneo_setEventLimit(size_t newLimit) {
icsneo::SetEventLimit(newLimit);
}
size_t icsneo_getErrorLimit(void) {
return icsneo::GetErrorLimit();
size_t icsneo_getEventLimit(void) {
return icsneo::GetEventLimit();
}
bool icsneo_getSupportedDevices(devicetype_t* devices, size_t* count) {
if(count == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
@@ -589,7 +598,7 @@ bool icsneo_getSupportedDevices(devicetype_t* devices, size_t* count) {
if(*count < len) {
len = *count;
ErrorManager::GetInstance().add(APIError::OutputTruncated);
EventManager::GetInstance().add(APIEvent::Type::OutputTruncated, APIEvent::Severity::EventWarning);
}
for(size_t i = 0; i < len; i++)
@@ -599,15 +608,12 @@ bool icsneo_getSupportedDevices(devicetype_t* devices, size_t* count) {
return true;
}
extern bool DLLExport icsneo_getTimestampResolution(const neodevice_t* device, uint16_t* resolution)
{
if (!icsneo_isValidNeoDevice(device)) {
ErrorManager::GetInstance().add(APIError::InvalidNeoDevice);
extern bool DLLExport icsneo_getTimestampResolution(const neodevice_t* device, uint16_t* resolution) {
if(!icsneo_isValidNeoDevice(device))
return false;
}
if (resolution == nullptr) {
ErrorManager::GetInstance().add(APIError::RequiredParameterNull);
if(resolution == nullptr) {
EventManager::GetInstance().add(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
-183
View File
@@ -1,183 +0,0 @@
#include "icsneo/api/error.h"
#include "icsneo/device/device.h"
#include <sstream>
using namespace icsneo;
APIError::APIError(ErrorType error) : errorStruct({}) {
init(error);
}
APIError::APIError(ErrorType error, const Device* forDevice) : errorStruct({}) {
device = forDevice;
serial = device->getSerial();
errorStruct.serial[serial.copy(errorStruct.serial, sizeof(errorStruct.serial))] = '\0';
init(error);
}
void APIError::init(ErrorType error) {
timepoint = ErrorClock::now();
errorStruct.description = DescriptionForType(error);
errorStruct.errorNumber = (uint32_t)error;
errorStruct.severity = (uint8_t)SeverityForType(error);
errorStruct.timestamp = ErrorClock::to_time_t(timepoint);
}
std::string APIError::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
ss << " Error: ";
ss << getDescription();
return ss.str();
}
bool APIError::isForDevice(std::string filterSerial) const noexcept {
if(!device || filterSerial.length() == 0)
return false;
return device->getSerial() == filterSerial;
}
// API Errors
static constexpr const char* ERROR_INVALID_NEODEVICE = "The provided neodevice_t object was invalid.";
static constexpr const char* ERROR_REQUIRED_PARAMETER_NULL = "A required parameter was NULL.";
static constexpr const char* ERROR_BUFFER_INSUFFICIENT = "The provided buffer was insufficient. No data was written.";
static constexpr const char* ERROR_OUTPUT_TRUNCATED = "The output was too large for the provided buffer and has been truncated.";
static constexpr const char* ERROR_PARAMETER_OUT_OF_RANGE = "A parameter was out of range.";
// Device Errors
static constexpr const char* ERROR_POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
static constexpr const char* ERROR_NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered with 12 volts?";
static constexpr const char* ERROR_INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* ERROR_SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* ERROR_SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* ERROR_SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* ERROR_SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* ERROR_SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
// Transport Errors
static constexpr const char* ERROR_FAILED_TO_READ = "A read operation failed.";
static constexpr const char* ERROR_FAILED_TO_WRITE = "A write operation failed.";
static constexpr const char* ERROR_DRIVER_FAILED_TO_OPEN = "The device driver encountered a low-level error while opening the device.";
static constexpr const char* ERROR_PACKET_CHECKSUM_ERROR = "There was a checksum error while decoding a packet. The packet was dropped.";
static constexpr const char* ERROR_TRANSMIT_BUFFER_FULL = "The transmit buffer is full and the device is set to non-blocking.";
static constexpr const char* ERROR_PCAP_COULD_NOT_START = "The PCAP driver could not be started. Ethernet devices will not be found.";
static constexpr const char* ERROR_PCAP_COULD_NOT_FIND_DEVICES = "The PCAP driver failed to find devices. Ethernet devices will not be found.";
static constexpr const char* ERROR_TOO_MANY_ERRORS = "Too many errors have occurred. The list has been truncated.";
static constexpr const char* ERROR_UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* ERROR_INVALID = "An invalid internal error occurred.";
const char* APIError::DescriptionForType(ErrorType type) {
switch(type) {
// API Errors
case InvalidNeoDevice:
return ERROR_INVALID_NEODEVICE;
case RequiredParameterNull:
return ERROR_REQUIRED_PARAMETER_NULL;
case BufferInsufficient:
return ERROR_BUFFER_INSUFFICIENT;
case OutputTruncated:
return ERROR_OUTPUT_TRUNCATED;
case ParameterOutOfRange:
return ERROR_PARAMETER_OUT_OF_RANGE;
// Device Errors
case PollingMessageOverflow:
return ERROR_POLLING_MESSAGE_OVERFLOW;
case NoSerialNumber:
return ERROR_NO_SERIAL_NUMBER;
case IncorrectSerialNumber:
return ERROR_INCORRECT_SERIAL_NUMBER;
case SettingsReadError:
return ERROR_SETTINGS_READ;
case SettingsVersionError:
return ERROR_SETTINGS_VERSION;
case SettingsLengthError:
return ERROR_SETTINGS_LENGTH;
case SettingsChecksumError:
return ERROR_SETTINGS_CHECKSUM;
case SettingsNotAvailable:
return ERROR_SETTINGS_NOT_AVAILABLE;
// Transport Errors
case FailedToRead:
return ERROR_FAILED_TO_READ;
case FailedToWrite:
return ERROR_FAILED_TO_WRITE;
case DriverFailedToOpen:
return ERROR_DRIVER_FAILED_TO_OPEN;
case PacketChecksumError:
return ERROR_PACKET_CHECKSUM_ERROR;
case TransmitBufferFull:
return ERROR_TRANSMIT_BUFFER_FULL;
case PCAPCouldNotStart:
return ERROR_PCAP_COULD_NOT_START;
case PCAPCouldNotFindDevices:
return ERROR_PCAP_COULD_NOT_FIND_DEVICES;
// Other Errors
case TooManyErrors:
return ERROR_TOO_MANY_ERRORS;
case Unknown:
return ERROR_UNKNOWN;
default:
return ERROR_INVALID;
}
}
APIError::Severity APIError::SeverityForType(ErrorType type) {
switch(type) {
// API Warnings
case OutputTruncated:
// Device Warnings
case PollingMessageOverflow:
// Transport Warnings
case PCAPCouldNotStart:
case PCAPCouldNotFindDevices:
return Severity::Warning;
// API Errors
case InvalidNeoDevice:
case RequiredParameterNull:
case BufferInsufficient:
case ParameterOutOfRange:
// Device Errors
case NoSerialNumber:
case IncorrectSerialNumber:
case SettingsReadError:
case SettingsVersionError:
case SettingsLengthError:
case SettingsChecksumError:
case SettingsNotAvailable:
// Transport Errors
case FailedToRead:
case FailedToWrite:
case DriverFailedToOpen:
case PacketChecksumError:
case TransmitBufferFull:
// Other Errors
case TooManyErrors:
case Unknown:
default:
return Severity::Error;
}
}
bool ErrorFilter::match(const APIError& error) const noexcept {
if(type != APIError::Any && type != error.getType())
return false;
if(matchOnDevicePtr && !error.isForDevice(device))
return false;
if(severity != APIError::Severity::Any && severity != error.getSeverity())
return false;
if(serial.length() != 0 && !error.isForDevice(serial))
return false;
return true;
}
-146
View File
@@ -1,146 +0,0 @@
#include "icsneo/api/errormanager.h"
#include <memory>
using namespace icsneo;
static std::unique_ptr<ErrorManager> singleton;
ErrorManager& ErrorManager::GetInstance() {
if(!singleton)
singleton = std::unique_ptr<ErrorManager>(new ErrorManager());
return *singleton.get();
}
void ErrorManager::get(std::vector<APIError>& errorOutput, size_t max, ErrorFilter filter) {
std::lock_guard<std::mutex> lk(mutex);
if(max == 0) // A limit of 0 indicates no limit
max = (size_t)-1;
size_t count = 0;
errorOutput.clear();
auto it = errors.begin();
while(it != errors.end()) {
if(filter.match(*it)) {
errorOutput.push_back(*it);
errors.erase(it++);
if(count++ >= max)
break; // We now have as many written to output as we can
} else {
std::advance(it, 1);
}
}
}
bool ErrorManager::getLastError(APIError& errorOutput, ErrorFilter filter) {
std::lock_guard<std::mutex> lk(mutex);
auto it = errors.rbegin();
while(it != errors.rend()) {
if(filter.match(*it)) {
errorOutput = *it;
errors.erase(std::next(it).base());
return true;
}
std::advance(it, 1);
}
return false;
}
void ErrorManager::discard(ErrorFilter filter) {
std::lock_guard<std::mutex> lk(mutex);
errors.remove_if([&filter](const APIError& error) {
return filter.match(error);
});
}
size_t ErrorManager::count_internal(ErrorFilter filter) const {
size_t ret = 0;
for(auto& error : errors)
if(filter.match(error))
ret++;
return ret;
}
bool ErrorManager::beforeAddCheck(APIError::ErrorType type) {
if(enforceLimit()) { // The enforceLimit will add the "TooManyErrors" error for us if necessary
// We need to decide whether to add this error or drop it
// We would have to remove something if we added this error
if(APIError::SeverityForType(type) < lowestCurrentSeverity())
return false; // Don't add this one, we are already full of higher priority items
}
return true;
}
bool ErrorManager::enforceLimit() {
if(errors.size() + 1 < errorLimit)
return false;
bool hasTooManyWarningAlready = count_internal(ErrorFilter(APIError::TooManyErrors)) != 0;
size_t amountToRemove = (errors.size() + (hasTooManyWarningAlready ? 1 : 2)) - errorLimit;
discardLeastSevere(amountToRemove);
if(!hasTooManyWarningAlready)
errors.emplace_back(APIError::TooManyErrors);
return true;
}
APIError::Severity ErrorManager::lowestCurrentSeverity() {
if(errors.empty())
return APIError::Severity(0);
APIError::Severity lowest = APIError::Severity::Error;
auto it = errors.begin();
while(it != errors.end()) {
if((*it).getSeverity() < lowest)
lowest = (*it).getSeverity();
it++;
}
return lowest;
}
void ErrorManager::discardLeastSevere(size_t count) {
if(count == 0)
return;
ErrorFilter infoFilter(APIError::Severity::Info);
auto it = errors.begin();
while(it != errors.end()) {
if(infoFilter.match(*it)) {
errors.erase(it++);
if(--count == 0)
break;
} else {
it++;
}
}
if(count != 0) {
ErrorFilter warningFilter(APIError::Severity::Warning);
it = errors.begin();
while(it != errors.end()) {
if(warningFilter.match(*it)) {
errors.erase(it++);
if(--count == 0)
break;
} else {
it++;
}
}
}
if(count != 0) {
ErrorFilter errorFilter(APIError::Severity::Error);
it = errors.begin();
while(it != errors.end()) {
if(errorFilter.match(*it)) {
errors.erase(it++);
if(--count == 0)
break;
} else {
it++;
}
}
}
}
+231
View File
@@ -0,0 +1,231 @@
#include "icsneo/api/event.h"
#include "icsneo/device/device.h"
#include <sstream>
using namespace icsneo;
APIEvent::APIEvent(Type type, APIEvent::Severity severity, const Device* device) : eventStruct({}) {
this->device = device;
if(device) {
serial = device->getSerial();
eventStruct.serial[serial.copy(eventStruct.serial, sizeof(eventStruct.serial))] = '\0';
}
init(type, severity);
}
void APIEvent::init(Type event, APIEvent::Severity severity) {
timepoint = EventClock::now();
eventStruct.description = DescriptionForType(event);
eventStruct.eventNumber = (uint32_t)event;
eventStruct.severity = (uint8_t) severity;
eventStruct.timestamp = EventClock::to_time_t(timepoint);
}
std::string APIEvent::describe() const noexcept {
std::stringstream ss;
if(device)
ss << *device; // Makes use of device.describe()
else
ss << "API";
Severity severity = getSeverity();
if(severity == Severity::EventInfo) {
ss << " Info: ";
} else if(severity == Severity::EventWarning) {
ss << " Warning: ";
} else if(severity == Severity::Error) {
ss << " Error: ";
} else {
// Should never get here, since Severity::Any should only be used for filtering
ss << " Any: ";
}
ss << getDescription();
return ss.str();
}
void APIEvent::downgradeFromError() noexcept {
eventStruct.severity = (uint8_t) APIEvent::Severity::EventWarning;
}
bool APIEvent::isForDevice(std::string filterSerial) const noexcept {
if(!device || filterSerial.length() == 0)
return false;
return device->getSerial() == filterSerial;
}
// API Errors
static constexpr const char* INVALID_NEODEVICE = "The provided neodevice_t object was invalid.";
static constexpr const char* REQUIRED_PARAMETER_NULL = "A required parameter was NULL.";
static constexpr const char* OUTPUT_TRUNCATED = "The output was too large for the provided buffer and has been truncated.";
static constexpr const char* BUFFER_INSUFFICIENT = "The provided buffer was insufficient. No data was written.";
static constexpr const char* PARAMETER_OUT_OF_RANGE = "A parameter was out of range.";
static constexpr const char* DEVICE_CURRENTLY_OPEN = "The device is currently open.";
static constexpr const char* DEVICE_CURRENTLY_CLOSED = "The device is currently closed.";
static constexpr const char* DEVICE_CURRENTLY_ONLINE = "The device is currently online.";
static constexpr const char* DEVICE_CURRENTLY_OFFLINE = "The device is currently offline.";
static constexpr const char* DEVICE_CURRENTLY_POLLING = "The device is currently polling for messages.";
static constexpr const char* DEVICE_NOT_CURRENTLY_POLLING = "The device is not currently polling for messages.";
static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network.";
static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long.";
// Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
static constexpr const char* NO_SERIAL_NUMBER = "Communication could not be established with the device. Perhaps it is not powered with 12 volts?";
static constexpr const char* INCORRECT_SERIAL_NUMBER = "The device did not return the expected serial number!";
static constexpr const char* SETTINGS_READ = "The device settings could not be read.";
static constexpr const char* SETTINGS_VERSION = "The settings version is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* SETTINGS_LENGTH = "The settings length is incorrect, please update your firmware with neoVI Explorer.";
static constexpr const char* SETTINGS_CHECKSUM = "The settings checksum is incorrect, attempting to set defaults may remedy this issue.";
static constexpr const char* SETTINGS_NOT_AVAILABLE = "Settings are not available for this device.";
static constexpr const char* SETTINGS_READONLY = "Settings are read-only for this device.";
static constexpr const char* CAN_SETTINGS_NOT_AVAILABLE = "CAN settings are not available for this device.";
static constexpr const char* CANFD_SETTINGS_NOT_AVAILABLE = "CANFD settings are not available for this device.";
static constexpr const char* LSFTCAN_SETTINGS_NOT_AVAILABLE = "LSFTCAN settings are not available for this device.";
static constexpr const char* SWCAN_SETTINGS_NOT_AVAILABLE = "SWCAN settings are not available for this device.";
static constexpr const char* BAUDRATE_NOT_FOUND = "The baudrate was not found.";
static constexpr const char* UNEXPECTED_NETWORK_TYPE = "The network type was not found.";
static constexpr const char* DEVICE_FIRMWARE_OUT_OF_DATE = "The device firmware is out of date. New API functionality may not be supported.";
static constexpr const char* SETTINGS_STRUCTURE_MISMATCH = "Unexpected settings structure for this device.";
static constexpr const char* SETTINGS_STRUCTURE_TRUNCATED = "Settings structure is longer than the device supports and will be truncated.";
static constexpr const char* NO_DEVICE_RESPONSE = "Expected a response from the device but none were found.";
static constexpr const char* MESSAGE_FORMATTING = "The message was not properly formed.";
static constexpr const char* CANFD_NOT_SUPPORTED = "This device does not support CANFD.";
static constexpr const char* RTR_NOT_SUPPORTED = "RTR is not supported with CANFD.";
// Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
static constexpr const char* FAILED_TO_WRITE = "A write operation failed.";
static constexpr const char* DRIVER_FAILED_TO_OPEN = "The device driver encountered a low-level error while opening the device.";
static constexpr const char* DRIVER_FAILED_TO_CLOSE = "The device driver encountered a low-level error while closing the device.";
static constexpr const char* PACKET_CHECKSUM_ERROR = "There was a checksum error while decoding a packet. The packet was dropped.";
static constexpr const char* TRANSMIT_BUFFER_FULL = "The transmit buffer is full and the device is set to non-blocking.";
static constexpr const char* PCAP_COULD_NOT_START = "The PCAP driver could not be started. Ethernet devices will not be found.";
static constexpr const char* PCAP_COULD_NOT_FIND_DEVICES = "The PCAP driver failed to find devices. Ethernet devices will not be found.";
static constexpr const char* PACKET_DECODING = "The packet could not be decoded.";
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
static constexpr const char* INVALID = "An invalid internal error occurred.";
const char* APIEvent::DescriptionForType(Type type) {
switch(type) {
// API Errors
case Type::InvalidNeoDevice:
return INVALID_NEODEVICE;
case Type::RequiredParameterNull:
return REQUIRED_PARAMETER_NULL;
case Type::BufferInsufficient:
return BUFFER_INSUFFICIENT;
case Type::OutputTruncated:
return OUTPUT_TRUNCATED;
case Type::ParameterOutOfRange:
return PARAMETER_OUT_OF_RANGE;
case Type::DeviceCurrentlyOpen:
return DEVICE_CURRENTLY_OPEN;
case Type::DeviceCurrentlyClosed:
return DEVICE_CURRENTLY_CLOSED;
case Type::DeviceCurrentlyOnline:
return DEVICE_CURRENTLY_ONLINE;
case Type::DeviceCurrentlyOffline:
return DEVICE_CURRENTLY_OFFLINE;
case Type::DeviceCurrentlyPolling:
return DEVICE_CURRENTLY_POLLING;
case Type::DeviceNotCurrentlyPolling:
return DEVICE_NOT_CURRENTLY_POLLING;
case Type::UnsupportedTXNetwork:
return UNSUPPORTED_TX_NETWORK;
case Type::MessageMaxLengthExceeded:
return MESSAGE_MAX_LENGTH_EXCEEDED;
// Device Errors
case Type::PollingMessageOverflow:
return POLLING_MESSAGE_OVERFLOW;
case Type::NoSerialNumber:
return NO_SERIAL_NUMBER;
case Type::IncorrectSerialNumber:
return INCORRECT_SERIAL_NUMBER;
case Type::SettingsReadError:
return SETTINGS_READ;
case Type::SettingsVersionError:
return SETTINGS_VERSION;
case Type::SettingsLengthError:
return SETTINGS_LENGTH;
case Type::SettingsChecksumError:
return SETTINGS_CHECKSUM;
case Type::SettingsNotAvailable:
return SETTINGS_NOT_AVAILABLE;
case Type::SettingsReadOnly:
return SETTINGS_READONLY;
case Type::CANSettingsNotAvailable:
return CAN_SETTINGS_NOT_AVAILABLE;
case Type::CANFDSettingsNotAvailable:
return CANFD_SETTINGS_NOT_AVAILABLE;
case Type::LSFTCANSettingsNotAvailable:
return LSFTCAN_SETTINGS_NOT_AVAILABLE;
case Type::SWCANSettingsNotAvailable:
return SWCAN_SETTINGS_NOT_AVAILABLE;
case Type::BaudrateNotFound:
return BAUDRATE_NOT_FOUND;
case Type::UnexpectedNetworkType:
return UNEXPECTED_NETWORK_TYPE;
case Type::DeviceFirmwareOutOfDate:
return DEVICE_FIRMWARE_OUT_OF_DATE;
case Type::SettingsStructureMismatch:
return SETTINGS_STRUCTURE_MISMATCH;
case Type::SettingsStructureTruncated:
return SETTINGS_STRUCTURE_TRUNCATED;
case Type::NoDeviceResponse:
return NO_DEVICE_RESPONSE;
case Type::MessageFormattingError:
return MESSAGE_FORMATTING;
case Type::CANFDNotSupported:
return CANFD_NOT_SUPPORTED;
case Type::RTRNotSupported:
return RTR_NOT_SUPPORTED;
// Transport Errors
case Type::FailedToRead:
return FAILED_TO_READ;
case Type::FailedToWrite:
return FAILED_TO_WRITE;
case Type::DriverFailedToOpen:
return DRIVER_FAILED_TO_OPEN;
case Type::DriverFailedToClose:
return DRIVER_FAILED_TO_CLOSE;
case Type::PacketChecksumError:
return PACKET_CHECKSUM_ERROR;
case Type::TransmitBufferFull:
return TRANSMIT_BUFFER_FULL;
case Type::PCAPCouldNotStart:
return PCAP_COULD_NOT_START;
case Type::PCAPCouldNotFindDevices:
return PCAP_COULD_NOT_FIND_DEVICES;
case Type::PacketDecodingError:
return PACKET_DECODING;
// Other Errors
case Type::TooManyEvents:
return TOO_MANY_EVENTS;
case Type::Unknown:
return UNKNOWN;
default:
return INVALID;
}
}
bool EventFilter::match(const APIEvent& event) const noexcept {
if(type != APIEvent::Type::Any && type != event.getType())
return false;
if(matchOnDevicePtr && !event.isForDevice(device))
return false;
if(severity != APIEvent::Severity::Any && severity != event.getSeverity())
return false;
if(serial.length() != 0 && !event.isForDevice(serial))
return false;
return true;
}
+142
View File
@@ -0,0 +1,142 @@
#include "icsneo/api/eventmanager.h"
#include <memory>
using namespace icsneo;
EventManager& EventManager::GetInstance() {
static EventManager inst;
return inst;
}
void EventManager::ResetInstance() {
std::lock_guard<std::mutex> eventsLock(eventsMutex);
std::lock_guard<std::mutex> errorsLock(errorsMutex);
std::lock_guard<std::mutex> downgradedThreadsLock(downgradedThreadsMutex);
std::lock_guard<std::mutex> callbacksLock(callbacksMutex);
std::lock_guard<std::mutex> callbackIDLock(callbackIDMutex);
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
events.clear();
lastUserErrors.clear();
downgradedThreads.clear();
callbacks.clear();
callbackID = 0;
eventLimit = 10000;
}
int EventManager::addEventCallback(const EventCallback &cb) {
std::lock_guard<std::mutex> callbacksLock(callbacksMutex);
std::lock_guard<std::mutex> callbackIDLock(callbackIDMutex);
callbacks.insert({callbackID, cb});
return callbackID++;
}
bool EventManager::removeEventCallback(int id) {
std::lock_guard<std::mutex> lk(callbacksMutex);
auto iter = callbacks.find(id);
if(iter != callbacks.end()) {
callbacks.erase(iter);
return true;
} else
return false;
}
bool EventManager::isDowngradingErrorsOnCurrentThread() const {
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
return i->second;
}
return false;
}
void EventManager::get(std::vector<APIEvent>& eventOutput, size_t max, EventFilter filter) {
std::lock_guard<std::mutex> lk(eventsMutex);
if(max == 0) // A limit of 0 indicates no limit
max = (size_t)-1;
size_t count = 0;
eventOutput.clear();
auto it = events.begin();
while(it != events.end()) {
if(filter.match(*it)) {
eventOutput.push_back(*it);
it = events.erase(it);
if(++count >= max)
break; // We now have as many written to output as we can
} else {
it++;
}
}
}
/**
* Removes the returned error from the map
* If no error was found, return a NoErrorFound Info event
*/
APIEvent EventManager::getLastError() {
std::lock_guard<std::mutex> lk(errorsMutex);
auto it = lastUserErrors.find(std::this_thread::get_id());
if(it == lastUserErrors.end()) {
return APIEvent(APIEvent::Type::NoErrorFound, APIEvent::Severity::EventInfo);
} else {
APIEvent ret = it->second;
it = lastUserErrors.erase(it);
return ret;
}
}
void EventManager::discard(EventFilter filter) {
std::lock_guard<std::mutex> lk(eventsMutex);
events.remove_if([&filter](const APIEvent& event) {
return filter.match(event);
});
}
size_t EventManager::count_internal(EventFilter filter) const {
size_t ret = 0;
for(auto& event : events)
if(filter.match(event))
ret++;
return ret;
}
/**
* Ensures events is always at most eventLimit - 1 in size.
* Returns true if any events were removed in the process of doing so.
*/
bool EventManager::enforceLimit() {
// Remove all TooManyEvents from the end before checking
auto filter = EventFilter(APIEvent::Type::TooManyEvents);
auto it = events.rbegin();
while(it != events.rend() && filter.match(*it)) {
it = decltype(it){events.erase( std::next(it).base() )};
}
// We are not overflowing
if(events.size() < eventLimit)
return false;
size_t amountToRemove = events.size() + 1 - eventLimit;
discardOldest(amountToRemove);
return true;
}
void EventManager::discardOldest(size_t count) {
if(count == 0)
return;
auto it = events.begin();
while(it != events.end()) {
it = events.erase(it);
if(--count == 0)
break;
}
}
+18 -18
View File
@@ -11,38 +11,38 @@ std::vector<DeviceType> icsneo::GetSupportedDevices() {
return DeviceFinder::GetSupportedDevices();
}
size_t icsneo::ErrorCount(ErrorFilter filter) {
return ErrorManager::GetInstance().count(filter);
size_t icsneo::EventCount(EventFilter filter) {
return EventManager::GetInstance().eventCount(filter);
}
std::vector<APIError> icsneo::GetErrors(ErrorFilter filter, size_t max) {
return ErrorManager::GetInstance().get(filter, max);
std::vector<APIEvent> icsneo::GetEvents(EventFilter filter, size_t max) {
return EventManager::GetInstance().get(filter, max);
}
std::vector<APIError> icsneo::GetErrors(size_t max, ErrorFilter filter) {
return ErrorManager::GetInstance().get(max, filter);
std::vector<APIEvent> icsneo::GetEvents(size_t max, EventFilter filter) {
return EventManager::GetInstance().get(max, filter);
}
void icsneo::GetErrors(std::vector<APIError>& errors, ErrorFilter filter, size_t max) {
ErrorManager::GetInstance().get(errors, filter, max);
void icsneo::GetEvents(std::vector<APIEvent>& events, EventFilter filter, size_t max) {
EventManager::GetInstance().get(events, filter, max);
}
void icsneo::GetErrors(std::vector<APIError>& errors, size_t max, ErrorFilter filter) {
ErrorManager::GetInstance().get(errors, max, filter);
void icsneo::GetEvents(std::vector<APIEvent>& events, size_t max, EventFilter filter) {
EventManager::GetInstance().get(events, max, filter);
}
bool icsneo::GetLastError(APIError& error, ErrorFilter filter) {
return ErrorManager::GetInstance().getLastError(error, filter);
APIEvent icsneo::GetLastError() {
return EventManager::GetInstance().getLastError();
}
void icsneo::DiscardErrors(ErrorFilter filter) {
ErrorManager::GetInstance().discard(filter);
void icsneo::DiscardEvents(EventFilter filter) {
EventManager::GetInstance().discard(filter);
}
void icsneo::SetErrorLimit(size_t newLimit) {
ErrorManager::GetInstance().setErrorLimit(newLimit);
void icsneo::SetEventLimit(size_t newLimit) {
EventManager::GetInstance().setEventLimit(newLimit);
}
size_t icsneo::GetErrorLimit() {
return ErrorManager::GetInstance().getErrorLimit();
size_t icsneo::GetEventLimit() {
return EventManager::GetInstance().getEventLimit();
}
+9 -10
View File
@@ -163,9 +163,8 @@ int icsneoOpenNeoDevice(NeoDevice* pNeoDevice, void** hObject, unsigned char* bN
*hObject = device;
if(!icsneo_openDevice(device))
return false;
icsneo_setPollingMessageLimit(device, 20000);
icsneo_enableMessagePolling(device);
return icsneo_goOnline(device);
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
}
int icsneoClosePort(void* hObject, int* pNumberOfErrors) {
@@ -293,7 +292,7 @@ int icsneoGetFireSettings(void* hObject, SFireSettings* pSettings, int iNumBytes
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetFireSettings(void* hObject, SFireSettings* pSettings, int iNumBytes, int bSaveToEEPROM) {
@@ -309,7 +308,7 @@ int icsneoGetVCAN3Settings(void* hObject, SVCAN3Settings* pSettings, int iNumByt
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetVCAN3Settings(void* hObject, SVCAN3Settings* pSettings, int iNumBytes, int bSaveToEEPROM) {
@@ -325,7 +324,7 @@ int icsneoGetFire2Settings(void* hObject, SFire2Settings* pSettings, int iNumByt
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetFire2Settings(void* hObject, SFire2Settings* pSettings, int iNumBytes, int bSaveToEEPROM) {
@@ -341,7 +340,7 @@ int icsneoGetVCANRFSettings(void* hObject, SVCANRFSettings* pSettings, int iNumB
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetVCANRFSettings(void* hObject, SVCANRFSettings* pSettings, int iNumBytes, int bSaveToEEPROM) {
@@ -357,7 +356,7 @@ int icsneoGetVCAN412Settings(void* hObject, SVCAN412Settings* pSettings, int iNu
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetVCAN412Settings(void* hObject, SVCAN412Settings* pSettings, int iNumBytes, int bSaveToEEPROM) {
@@ -373,7 +372,7 @@ int icsneoGetRADGalaxySettings(void* hObject, SRADGalaxySettings* pSettings, int
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetRADGalaxySettings(void* hObject, SRADGalaxySettings* pSettings, int iNumBytes, int bSaveToEEPROM) {
@@ -389,7 +388,7 @@ int icsneoGetRADStar2Settings(void* hObject, SRADStar2Settings* pSettings, int i
if(!icsneoValidateHObject(hObject))
return false;
neodevice_t* device = (neodevice_t*)hObject;
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
}
int icsneoSetRADStar2Settings(void* hObject, SRADStar2Settings* pSettings, int iNumBytes, int bSaveToEEPROM) {
+45 -19
View File
@@ -18,11 +18,12 @@ using namespace icsneo;
int Communication::messageCallbackIDCounter = 1;
bool Communication::open() {
if(isOpen)
return true;
if(isOpen()) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
return false;
}
spawnThreads();
isOpen = true;
return impl->open();
}
@@ -38,15 +39,20 @@ void Communication::joinThreads() {
}
bool Communication::close() {
if(!isOpen)
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
isOpen = false;
joinThreads();
return impl->close();
}
bool Communication::isOpen() {
return impl->isOpen();
}
bool Communication::sendPacket(std::vector<uint8_t>& bytes) {
// This is here so that other communication types (like multichannel) can override it
return rawWrite(bytes);
@@ -67,12 +73,16 @@ bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::mil
return false;
std::shared_ptr<ReadSettingsMessage> gsmsg = std::dynamic_pointer_cast<ReadSettingsMessage>(msg);
if(!gsmsg)
if(!gsmsg) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false;
}
if(gsmsg->response != ReadSettingsMessage::Response::OK)
if(gsmsg->response != ReadSettingsMessage::Response::OK) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false;
}
data = std::move(msg->data);
return true;
}
@@ -91,15 +101,18 @@ std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chr
}
int Communication::addMessageCallback(const MessageCallback& cb) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb));
return messageCallbackIDCounter++;
}
bool Communication::removeMessageCallback(int id) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
try {
messageCallbacks.erase(id);
return true;
} catch(...) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false;
}
}
@@ -118,7 +131,8 @@ std::shared_ptr<Message> Communication::waitForMessageSync(std::shared_ptr<Messa
// We have now added the callback, wait for it to return from the other thread
std::unique_lock<std::mutex> lk(m);
cv.wait_for(lk, timeout, [&returnedMessage]{ return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value
cv.wait_for(lk, timeout, [&returnedMessage] { return !!returnedMessage; }); // `!!shared_ptr` checks if the ptr has a value
lk.unlock();
// We don't actually check that we got a message, because either way we want to remove the callback (since it should only happen once)
removeMessageCallback(cb);
@@ -127,25 +141,37 @@ std::shared_ptr<Message> Communication::waitForMessageSync(std::shared_ptr<Messa
return returnedMessage;
}
void Communication::dispatchMessage(const std::shared_ptr<Message>& msg) {
std::lock_guard<std::mutex> lk(messageCallbacksLock);
// We want callbacks to be able to access errors
const bool downgrade = EventManager::GetInstance().isDowngradingErrorsOnCurrentThread();
if(downgrade)
EventManager::GetInstance().cancelErrorDowngradingOnCurrentThread();
for(auto& cb : messageCallbacks) {
if(!closing) { // We might have closed while reading or processing
cb.second.callIfMatch(msg);
}
}
if(downgrade)
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
}
void Communication::readTask() {
std::vector<uint8_t> readBytes;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
readBytes.clear();
if(impl->readWait(readBytes)) {
if(packetizer->input(readBytes)) {
for(auto& packet : packetizer->output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet)) {
err(APIError::Unknown); // TODO Use specific error
if(!decoder->decode(msg, packet))
continue;
}
for(auto& cb : messageCallbacks) {
if(!closing) { // We might have closed while reading or processing
cb.second.callIfMatch(msg);
}
}
dispatchMessage(msg);
}
}
}
+40 -5
View File
@@ -3,10 +3,12 @@
#include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/flexraypacket.h"
#include <iostream>
using namespace icsneo;
@@ -22,8 +24,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
switch(packet->network.getType()) {
case Network::Type::Ethernet:
result = HardwareEthernetPacket::DecodeToMessage(packet->data);
if(!result)
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was not long enough to decode
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
@@ -33,13 +37,33 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case Network::Type::CAN:
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
if(packet->data.size() < 24)
if(packet->data.size() < 24) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = HardwareCANPacket::DecodeToMessage(packet->data);
if(!result)
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
result->timestamp *= timestampResolution;
result->network = packet->network;
return true;
}
case Network::Type::FlexRay: {
if(packet->data.size() < 24) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = HardwareFlexRayPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device
result->timestamp *= timestampResolution;
@@ -49,8 +73,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case Network::Type::Internal: {
switch(packet->network.getNetID()) {
case Network::NetID::Reset_Status: {
if(packet->data.size() < sizeof(HardwareResetStatusPacket))
if(packet->data.size() < sizeof(HardwareResetStatusPacket)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
auto msg = std::make_shared<ResetStatusMessage>();
@@ -75,6 +101,15 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg;
return true;
}
case Network::NetID::FlexRayControl: {
auto frResult = std::make_shared<FlexRayControlMessage>(*packet);
if(!frResult->decoded) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
result = frResult;
return true;
}
default:
break;//return false;
}
@@ -111,7 +146,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
/* So-called "old format" messages are a "new style, long format" wrapper around the old short messages.
* They consist of a 16-bit LE length first, then the 8-bit length and netid combo byte, then the payload
* with no checksum. The upper-nibble length of the combo byte should be ignored completely, using the
* length from the first two bytes in it's place. Ideally, we never actually send the oldformat messages
* length from the first two bytes in its place. Ideally, we never actually send the oldformat messages
* out to the rest of the application as they can recursively get decoded to another message type here.
* Feed the result back into the decoder in case we do something special with the resultant netid.
*/
+35 -10
View File
@@ -13,11 +13,13 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
switch(message->network.getType()) {
case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg)
if(!ethmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed EthernetMessage
}
useResultAsBuffer = true;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result))
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
return false;
break;
@@ -26,14 +28,18 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
case Network::Type::SWCAN:
case Network::Type::LSFTCAN: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(!canmsg)
if(!canmsg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed CANMessage
}
if(!supportCANFD && canmsg->isCANFD)
if(!supportCANFD && canmsg->isCANFD) {
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
return false; // This device does not support CAN FD
}
useResultAsBuffer = true;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result))
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
return false; // The CANMessage was malformed
break;
@@ -69,6 +75,7 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
break;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
}
@@ -96,9 +103,27 @@ bool Encoder::encode(std::vector<uint8_t>& result, const std::shared_ptr<Message
bool Encoder::encode(std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments) {
auto msg = std::make_shared<Message>();
msg->network = Network::NetID::Main51;
msg->data.reserve(arguments.size() + 1);
msg->data.push_back((uint8_t)cmd);
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
if(cmd == Command::UpdateLEDState) {
/* NetID::Device is a super old command type.
* It has a leading 0x00 byte, a byte for command, and a byte for an argument.
* In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else.
*/
if (arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
msg->network = Network::NetID::Device;
msg->data.reserve(3);
msg->data.push_back(0x00);
msg->data.push_back(0x06); // SetLEDState
msg->data.push_back(arguments.at(0)); // See Device::LEDState
} else {
msg->network = Network::NetID::Main51;
msg->data.reserve(arguments.size() + 1);
msg->data.push_back((uint8_t)cmd);
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
}
return encode(result, msg);
}
+13 -4
View File
@@ -39,16 +39,25 @@ bool ICommunication::readWait(std::vector<uint8_t>& bytes, std::chrono::millisec
}
bool ICommunication::write(const std::vector<uint8_t>& bytes) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
if(writeBlocks) {
std::unique_lock<std::mutex> lk(writeMutex);
if(writeQueue.size_approx() > writeQueueSize) {
if(writeQueue.size_approx() > writeQueueSize)
writeCV.wait(lk);
}
} else {
if(writeQueue.size_approx() > writeQueueSize) {
err(APIError::TransmitBufferFull);
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
return false;
}
}
return writeQueue.enqueue(WriteOperation(bytes));
bool ret = writeQueue.enqueue(WriteOperation(bytes));
if(!ret)
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return ret;
}
@@ -0,0 +1,72 @@
#include <icsneo/communication/message/flexray/control/flexraycontrolmessage.h>
#include <cstring> // memcpy
#include <limits>
#include <algorithm>
using namespace icsneo;
std::vector<uint8_t> FlexRayControlMessage::BuildBaseControlArgs(uint8_t controller, FlexRay::Opcode op, std::initializer_list<uint8_t> args) {
std::vector<uint8_t> ret;
ret.reserve(args.size() + 4);
ret.push_back(controller);
const uint16_t size = uint16_t((std::min)(args.size() + 1, size_t(std::numeric_limits<uint16_t>::max()))); // Add 1 for the opcode
ret.push_back(uint8_t(size));
ret.push_back(uint8_t(size >> 8));
ret.push_back(uint8_t(op));
ret.insert(ret.end(), args.begin(), args.end());
return ret;
}
std::vector<uint8_t> FlexRayControlMessage::BuildReadCCRegsArgs(uint8_t controller, uint16_t startAddress, uint8_t numRegisters) {
startAddress /= 4;
return BuildBaseControlArgs(controller, FlexRay::Opcode::ReadCCRegs, {
uint8_t(startAddress),
uint8_t(startAddress >> 8),
numRegisters
});
}
std::vector<uint8_t> FlexRayControlMessage::BuildWriteCCRegArgs(uint8_t controller, uint16_t address, uint32_t value) {
address /= 4;
return BuildBaseControlArgs(controller, FlexRay::Opcode::ReadCCRegs, {
uint8_t(address),
uint8_t(address >> 8),
uint8_t(value),
uint8_t(value >> 8),
uint8_t(value >> 16),
uint8_t(value >> 24)
});
}
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() {
if(packet.data.size() < 2)
return; // huh?
controller = packet.data[0];
if(controller < 2)
return; // Invalid controller
// Opcode is only ReadCCStatus or ReadCCRegs for the moment
opcode = FlexRay::Opcode(packet.data[1]);
if(opcode != FlexRay::Opcode::ReadCCRegs && opcode != FlexRay::Opcode::ReadCCStatus)
return;
// Read out registers
size_t bytes = packet.data.size() - 2;
const size_t count = bytes / sizeof(uint32_t);
bytes -= bytes % sizeof(uint32_t); // trim off any trailing bytes
registers.resize(count);
memcpy(registers.data(), packet.data.data() + 2, bytes);
// If it was a status message, we should decode these registers into their components
if(opcode == FlexRay::Opcode::ReadCCStatus) {
if(count < 8)
return;
pocStatus = FlexRay::POCStatus(registers[0] & 0x0000003F);
slotCounterA = registers[4] & 0x0000FFFF;
slotCounterB = (registers[4] & 0xFFFF0000) >> 16;
rateCorrection = registers[6];
offsetCorrection = registers[7];
}
decoded = true;
}
+9 -11
View File
@@ -25,10 +25,13 @@ bool MultiChannelCommunication::sendPacket(std::vector<uint8_t>& bytes) {
void MultiChannelCommunication::readTask() {
bool readMore = true;
bool gotPacket = false; // Have we got the first valid packet (don't flag errors otherwise)
std::deque<uint8_t> usbReadFifo;
std::vector<uint8_t> readBytes;
std::vector<uint8_t> payloadBytes;
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
while(!closing) {
if(readMore) {
readBytes.clear();
@@ -47,8 +50,8 @@ void MultiChannelCommunication::readTask() {
currentCommandType = (CommandType)usbReadFifo[0];
if(!CommandTypeIsValid(currentCommandType)) {
// TODO Flag error? Device to host bytes discarded
//std::cout << "cnv" << std::hex << (int)currentCommandType << ' ' << std::dec;
// Device to host bytes discarded
EventManager::GetInstance().add(APIEvent(APIEvent::Type::FailedToRead, APIEvent::Severity::Error));
usbReadFifo.pop_front();
continue;
}
@@ -106,16 +109,11 @@ void MultiChannelCommunication::readTask() {
if(packetizer->input(payloadBytes)) {
for(auto& packet : packetizer->output()) {
std::shared_ptr<Message> msg;
if(!decoder->decode(msg, packet)) {
err(APIError::Unknown); // TODO Use specific error
continue;
}
if(!decoder->decode(msg, packet))
continue; // Error will have been reported from within decoder
for(auto& cb : messageCallbacks) { // We might have closed while reading or processing
if(!closing) {
cb.second.callIfMatch(msg);
}
}
gotPacket = true;
dispatchMessage(msg);
}
}
+14 -5
View File
@@ -79,13 +79,17 @@ std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector
return msg;
}
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result) {
if(message.isCANFD && message.isRemote)
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
if(message.isCANFD && message.isRemote) {
report(APIEvent::Type::RTRNotSupported, APIEvent::Severity::Error);
return false; // RTR frames can not be used with CAN FD
}
const size_t dataSize = message.data.size();
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD))
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD)) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol
}
uint8_t lengthNibble = uint8_t(message.data.size());
uint8_t paddingBytes = 0;
@@ -162,6 +166,7 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
lengthNibble = 0xF;
break;
default:
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // CAN FD frame may have had an incorrect byte count
}
}
@@ -176,8 +181,10 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
// Next 2-4 bytes are ArbID
if(message.isExtended) {
if(message.arbid >= 0x20000000) // Extended messages use 29-bit arb IDs
if(message.arbid >= 0x20000000) {// Extended messages use 29-bit arb IDs
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
result.insert(result.end(), {
(uint8_t)(message.arbid >> 21),
@@ -186,8 +193,10 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
(uint8_t)message.arbid
});
} else {
if(message.arbid >= 0x800) // Standard messages use 11-bit arb IDs
if(message.arbid >= 0x800) {// Standard messages use 11-bit arb IDs
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
result.insert(result.end(), {
(uint8_t)(message.arbid >> 3),
+1 -1
View File
@@ -53,7 +53,7 @@ std::shared_ptr<EthernetMessage> HardwareEthernetPacket::DecodeToMessage(const s
return messagePtr;
}
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream) {
bool HardwareEthernetPacket::EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t&) {
const size_t unpaddedSize = message.data.size();
size_t paddedSize = unpaddedSize;
+66
View File
@@ -0,0 +1,66 @@
#include "icsneo/communication/packet/flexraypacket.h"
using namespace icsneo;
std::shared_ptr<FlexRayMessage> HardwareFlexRayPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareFlexRayPacket* data = (const HardwareFlexRayPacket*)bytestream.data();
if(!data->timestamp.IsExtended) // We can only process "extended" frames here
return nullptr;
auto msg = std::make_shared<FlexRayMessage>();
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// Always get the frame length, even for a symbol
msg->framelen = data->frame_length_12_5ns * 12.5e-9;
if(data->tss_length_12_5ns == 0xffff) {// Flag value meaning this is a symbol
msg->symbol = FlexRay::Symbol::Unknown; // We can't know the symbol yet because this will depend on the baudrate
// Eventually we'll have to get this from the framelen
} else {
msg->tsslen = data->tss_length_12_5ns * 12.5e-9;
msg->channelB = data->statusBits.bits.chb;
if(data->statusBits.bits.bytesRxed >= 5) {
if(data->statusBits.bits.hcrc_error)
msg->headerCRCStatus = FlexRay::CRCStatus::Error;
} else {
msg->headerCRCStatus = FlexRay::CRCStatus::NoCRC;
}
uint32_t numBytes = data->payload_len * 2;
if(int64_t(numBytes) >= int64_t(data->Length) - 4) {
if(data->statusBits.bits.fcrc_error)
msg->crcStatus = FlexRay::CRCStatus::Error;
} else {
msg->crcStatus = FlexRay::CRCStatus::NoCRC;
}
if(data->statusBits.bits.bytesRxed >= 5) { // Received entire header
msg->headerCRC = (data->hdr_crc_10 << 10) | data->hdr_crc_9_0;
if(msg->headerCRCStatus != FlexRay::CRCStatus::Error) {
msg->reserved0was1 = data->reserved_0;
msg->payloadPreamble = data->payload_preamble;
msg->nullFrame = data->null_frame;
msg->sync = data->sync;
msg->startup = data->startup;
msg->slotid = data->slotid;
if(int64_t(numBytes) != int64_t(data->Length) - 4) {
} else {
// This is an error, probably need to flag it
}
}
}
}
return msg;
}
bool HardwareFlexRayPacket::EncodeFromMessage(const FlexRayMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report) {
(void)message;
(void)bytestream;
(void)report;
return false;
}
+38 -2
View File
@@ -41,6 +41,7 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
state = ReadState::ParseHeader;
currentIndex = 1;
} else {
std::cerr << "Discarding byte " << std::hex << std::setw(2) << std::setfill('0') << int(bytes.front()) << std::endl;
bytes.pop_front(); // Discard
}
break;
@@ -81,8 +82,23 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
* payload, and not the header or checksum.
*/
if(packetLength < 4 || packetLength > 4000) {
std::cerr << "====================================\n";
std::cerr << "An improper packet has occurred!\n";
std::cerr << "Packet: (" << std::dec << packetLength << ")\n";
std::cerr << '\t';
for(auto i = 0; i < std::min(packetLength, 16); i++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(bytes[i]) << ' ';
std::cerr << std::endl;
std::cerr << "Previous: (" << std::dec << previousPacket.data.size() << ") " << previousPacket.network << '\n';
for(auto i = 0; i < previousPacket.data.size(); i += 16) {
std::cerr << '\t';
for(auto j = 0; j < 16 && (i + j) < previousPacket.data.size(); j++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(previousPacket.data[i+j]) << ' ';
std::cerr << std::endl;
}
std::cerr << "====================================\n";
bytes.pop_front();
//std::cout << "skipping long packet with length " << packetLength << std::endl;
EventManager::GetInstance().add(APIEvent::Type::FailedToRead, APIEvent::Severity::Error);
state = ReadState::SearchForHeader;
} else {
state = ReadState::GetData;
@@ -111,9 +127,29 @@ bool Packetizer::input(const std::vector<uint8_t>& inputBytes) {
bytes.pop_front();
} else {
if(gotGoodPackets) // Don't complain unless we've already gotten a good packet, in case we started in the middle of a stream
err(APIError::PacketChecksumError);
report(APIEvent::Type::PacketChecksumError, APIEvent::Severity::Error);
std::cerr << "====================================\n";
std::cerr << "A checksum error has occurred!\n";
std::cerr << "Packet: (" << std::dec << packet.data.size() << ") " << packet.network << '\n';
for(auto i = 0; i < packet.data.size(); i += 16) {
std::cerr << '\t';
for(auto j = 0; j < 16 && (i + j) < packet.data.size(); j++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(packet.data[i+j]) << ' ';
std::cerr << std::endl;
}
std::cerr << "Previous: (" << std::dec << previousPacket.data.size() << ") " << previousPacket.network << '\n';
for(auto i = 0; i < previousPacket.data.size(); i += 16) {
std::cerr << '\t';
for(auto j = 0; j < 16 && (i + j) < previousPacket.data.size(); j++)
std::cerr << std::hex << std::setw(2) << std::setfill('0') << int(previousPacket.data[i+j]) << ' ';
std::cerr << std::endl;
}
std::cerr << "====================================\n";
bytes.pop_front(); // Drop the first byte so it doesn't get picked up again
}
previousPacket = packet;
// Reset for the next packet
currentIndex = 0;
+122 -35
View File
@@ -1,9 +1,11 @@
#include "icsneo/device/device.h"
#include "icsneo/communication/message/callback/messagecallback.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/communication/command.h"
#include <string.h>
#include <iostream>
#include <sstream>
#include <chrono>
using namespace icsneo;
@@ -77,33 +79,55 @@ std::string Device::describe() const {
return ss.str();
}
void Device::enableMessagePolling() {
if(messagePollingCallbackID != 0) // We are already polling
return;
bool Device::enableMessagePolling() {
if(isMessagePollingEnabled()) {// We are already polling
report(APIEvent::Type::DeviceCurrentlyPolling, APIEvent::Severity::Error);
return false;
}
messagePollingCallbackID = com->addMessageCallback(MessageCallback([this](std::shared_ptr<Message> message) {
pollingContainer.enqueue(message);
enforcePollingMessageLimit();
}));
return true;
}
bool Device::disableMessagePolling() {
if(messagePollingCallbackID == 0)
return true; // Not currently polling
if(!isMessagePollingEnabled()) {
report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error);
return false; // Not currently polling
}
auto ret = com->removeMessageCallback(messagePollingCallbackID);
getMessages(); // Flush any messages still in the container
messagePollingCallbackID = 0;
return ret;
}
std::vector<std::shared_ptr<Message>> Device::getMessages() {
// Returns a pair of {vector, bool}, where the vector contains shared_ptrs to the returned msgs and the bool is whether or not the call was successful.
std::pair<std::vector<std::shared_ptr<Message>>, bool> Device::getMessages() {
std::vector<std::shared_ptr<Message>> ret;
getMessages(ret);
return ret;
bool retBool = getMessages(ret);
return std::make_pair(ret, retBool);
}
bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) {
// not open
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
// not online
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return false;
}
// not currently polling, throw error
if(!isMessagePollingEnabled()) {
report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error);
return false;
}
// A limit of zero indicates no limit
if(limit == 0)
limit = (size_t)-1;
@@ -130,18 +154,19 @@ void Device::enforcePollingMessageLimit() {
while(pollingContainer.size_approx() > pollingMessageLimit) {
std::shared_ptr<Message> throwAway;
pollingContainer.try_dequeue(throwAway);
err(APIError::PollingMessageOverflow);
report(APIEvent::Type::PollingMessageOverflow, APIEvent::Severity::EventWarning);
}
}
bool Device::open() {
if(!com) {
err(APIError::Unknown);
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false;
}
if(!com->open())
if(!com->open()) {
return false;
}
auto serial = com->getSerialNumberSync();
int i = 0;
@@ -151,14 +176,14 @@ bool Device::open() {
break;
}
if(!serial) {
err(APIError::NoSerialNumber); // Communication could not be established with the device. Perhaps it is not powered with 12 volts?
report(APIEvent::Type::NoSerialNumber, APIEvent::Severity::Error); // Communication could not be established with the device. Perhaps it is not powered with 12 volts?
com->close();
return false;
}
std::string currentSerial = getNeoDevice().serial;
if(currentSerial != serial->deviceSerial) {
err(APIError::IncorrectSerialNumber);
report(APIEvent::Type::IncorrectSerialNumber, APIEvent::Severity::Error);
com->close();
return false;
}
@@ -166,7 +191,9 @@ bool Device::open() {
if(!settings->disabled)
settings->refresh();
internalHandlerCallbackID = com->addMessageCallback(MessageCallback(MessageFilter(Network::Type::Internal), [this](std::shared_ptr<Message> message) {
MessageFilter filter;
filter.includeInternalInAny = true;
internalHandlerCallbackID = com->addMessageCallback(MessageCallback(filter, [this](std::shared_ptr<Message> message) {
handleInternalMessage(message);
}));
@@ -175,14 +202,18 @@ bool Device::open() {
bool Device::close() {
if(!com) {
err(APIError::Unknown);
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
return false;
}
if(isOnline())
goOffline();
if(internalHandlerCallbackID)
com->removeMessageCallback(internalHandlerCallbackID);
goOffline();
internalHandlerCallbackID = 0;
return com->close();
}
@@ -190,10 +221,28 @@ bool Device::goOnline() {
if(!com->sendCommand(Command::EnableNetworkCommunication, true))
return false;
auto startTime = std::chrono::system_clock::now();
ledState = LEDState::Online;
updateLEDState();
MessageFilter filter(Network::NetID::Reset_Status);
filter.includeInternalInAny = true;
// Wait until communication is enabled or 5 seconds, whichever comes first
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
if(latestResetStatus && latestResetStatus->comEnabled)
break;
if(!com->sendCommand(Command::RequestStatusUpdate))
return false;
com->waitForMessageSync(filter, std::chrono::milliseconds(100));
}
online = true;
return true;
}
@@ -201,16 +250,48 @@ bool Device::goOffline() {
if(!com->sendCommand(Command::EnableNetworkCommunication, false))
return false;
ledState = (latestResetStatus && latestResetStatus->cmRunning) ? LEDState::CoreMiniRunning : LEDState::Offline;
updateLEDState();
auto startTime = std::chrono::system_clock::now();
ledState = (latestResetStatus && latestResetStatus->cmRunning) ? LEDState::CoreMiniRunning : LEDState::Offline;
updateLEDState();
MessageFilter filter(Network::NetID::Reset_Status);
filter.includeInternalInAny = true;
// wait until communication is disabled or 10 seconds, whichever comes first
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
if(latestResetStatus && !latestResetStatus->comEnabled)
break;
if(!com->sendCommand(Command::RequestStatusUpdate))
return false;
com->waitForMessageSync(filter, std::chrono::milliseconds(100));
}
online = false;
return true;
}
bool Device::transmit(std::shared_ptr<Message> message) {
if(!isSupportedTXNetwork(message->network))
// not open
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false;
}
// not online
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return false;
}
if(!isSupportedTXNetwork(message->network)) {
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
return false;
}
std::vector<uint8_t> packet;
if(!com->encoder->encode(packet, message))
@@ -227,6 +308,10 @@ bool Device::transmit(std::vector<std::shared_ptr<Message>> messages) {
return true;
}
void Device::setWriteBlocks(bool blocks) {
com->setWriteBlocks(blocks);
}
size_t Device::getNetworkCountByType(Network::Type type) const {
size_t count = 0;
for(const auto& net : getSupportedRXNetworks())
@@ -248,6 +333,17 @@ Network Device::getNetworkByNumber(Network::Type type, size_t index) const {
return Network::NetID::Invalid;
}
void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) {
std::lock_guard<std::mutex> lk(extensionsLock);
extensions.push_back(extension);
}
void Device::forEachExtension(std::function<void(const std::shared_ptr<DeviceExtension>&)> fn) {
std::lock_guard<std::mutex> lk(extensionsLock);
for(const auto& ext : extensions)
fn(ext);
}
void Device::handleInternalMessage(std::shared_ptr<Message> message) {
switch(message->network.getNetID()) {
case Network::NetID::Reset_Status:
@@ -256,21 +352,12 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
default:
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
}
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
ext->handleMessage(message);
});
}
void Device::updateLEDState() {
/* NetID::Device is a super old command type.
* It has a leading 0x00 byte, a byte for command, and a byte for an argument.
* In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else.
*/
auto msg = std::make_shared<Message>();
msg->network = Network::NetID::Device;
msg->data = {0x00, 0x06, uint8_t(ledState)};
std::vector<uint8_t> packet;
if(!com->encoder->encode(packet, msg))
return;
com->sendPacket(packet);
std::vector<uint8_t> args {(uint8_t) ledState};
com->sendCommand(Command::UpdateLEDState, args);
}
+120
View File
@@ -0,0 +1,120 @@
#include "icsneo/device/extensions/flexray/controller.h"
#include "icsneo/device/device.h"
using namespace icsneo;
std::shared_ptr<FlexRayControlMessage> FlexRay::Controller::getStatus() const {
std::lock_guard<std::mutex> lk(statusLock);
return status;
}
void FlexRay::Controller::_setStatus(std::shared_ptr<FlexRayControlMessage> msg) {
std::lock_guard<std::mutex> lk(statusLock);
status = msg;
}
void FlexRay::Controller::getReady() {
}
void FlexRay::Controller::start() {
if(true) // TODO something
getReady();
if(wakeupBeforeStart)
setCurrentPOCCommand(FlexRay::POCCommand::Wakeup);
if(allowColdstart)
setCurrentPOCCommand(FlexRay::POCCommand::AllowColdstart);
setCurrentPOCCommand(FlexRay::POCCommand::Run);
}
std::pair<bool, FlexRay::POCCommand> FlexRay::Controller::getCurrentPOCCommand(std::chrono::milliseconds timeout) const {
const auto val = readRegister(ERAYRegister::SUCC1, timeout);
return {val.first, FlexRay::POCCommand(val.second & 0x0000000F)};
}
bool FlexRay::Controller::setCurrentPOCCommand(FlexRay::POCCommand cmd, bool checkForSuccess, std::chrono::milliseconds timeout) {
const auto beforeWrite = std::chrono::steady_clock::now();
if(!writeRegister(ERAYRegister::SUCC1, uint32_t(cmd), true, timeout))
return false;
if(!checkForSuccess)
return true;
const auto writeDuration = std::chrono::steady_clock::now() - beforeWrite;
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(writeDuration - timeout);
if(timeout.count() <= 0)
return false; // Out of time!
return wasCommandSuccessful(timeout);
}
bool FlexRay::Controller::wasCommandSuccessful(std::chrono::milliseconds timeout) const {
const auto val = getCurrentPOCCommand(timeout);
return val.first && val.second != FlexRay::POCCommand::CommandNotAccepted;
}
std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, std::chrono::milliseconds timeout) const {
std::lock_guard<std::mutex> lk(readRegisterLock);
device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildReadCCRegsArgs(index, uint16_t(reg)));
std::shared_ptr<FlexRayControlMessage> resp;
const auto start = std::chrono::steady_clock::now();
while(!resp && (std::chrono::steady_clock::now() - start) < timeout) {
auto msg = device.com->waitForMessageSync(MessageFilter(icsneo::Network::NetID::FlexRayControl), timeout);
if(auto frmsg = std::dynamic_pointer_cast<FlexRayControlMessage>(msg)) {
if(frmsg->decoded && frmsg->controller == index && frmsg->opcode == FlexRay::Opcode::ReadCCRegs)
resp = frmsg;
}
}
if(resp)
return {true, resp->registers[0]};
else
return {false, 0};
}
uint32_t FlexRay::Controller::readRegisterOr(ERAYRegister reg, uint32_t defaultValue, std::chrono::milliseconds timeout) const {
auto ret = readRegister(reg, timeout);
return ret.first ? ret.second : defaultValue;
}
bool FlexRay::Controller::writeRegister(
ERAYRegister reg,
uint32_t value,
uint32_t mask,
bool waitForPOCReady,
std::chrono::milliseconds timeout) {
if(mask != 0xffffffff) {
const auto beforeRead = std::chrono::steady_clock::now();
auto pair = readRegister(reg, timeout);
if(!pair.first)
return false; // Couldn't read, so we don't want to try to write anything
auto readDuration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - beforeRead);
timeout = readDuration - timeout;
if(timeout.count() <= 0)
return false; // Out of time!
pair.second &= ~mask;
pair.second |= value & mask;
value = pair.second;
}
return writeRegister(reg, value, waitForPOCReady, timeout);
}
bool FlexRay::Controller::writeRegister(
ERAYRegister reg,
uint32_t value,
bool waitForPOCReady,
std::chrono::milliseconds timeout) {
if(waitForPOCReady) {
const auto start = std::chrono::steady_clock::now();
bool pocBusy = isPOCBusy();
while(pocBusy && (std::chrono::steady_clock::now() - start) < timeout) {
pocBusy = isPOCBusy();
}
if(pocBusy) // timeout
return false;
}
device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteCCRegArgs(index, uint16_t(reg), value));
return true; // Does the device send anything back to tell us this actually happened?
}
+31
View File
@@ -0,0 +1,31 @@
#include "icsneo/device/extensions/flexray/extension.h"
#include "icsneo/device/device.h"
using namespace icsneo;
FlexRay::Extension::Extension(Device& device, uint8_t controllerCount) : DeviceExtension(device) {
for(uint8_t i = 0; i < controllerCount; i++)
controllers.emplace_back(std::make_shared<FlexRay::Controller>(device, i));
}
void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) {
switch(message->network.getNetID()) {
case Network::NetID::FlexRayControl: {
auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message);
if(!msg || !msg->decoded)
return;
switch(msg->opcode) {
case FlexRay::Opcode::ReadCCStatus:
if(auto status = std::dynamic_pointer_cast<FlexRayControlMessage>(message)) { // TODO else report error?
if(status->controller >= controllers.size())
return; // TODO error
controllers[status->controller]->_setStatus(status);
}
break;
}
break;
}
default:
break;
}
}
+171 -45
View File
@@ -130,7 +130,7 @@ int64_t IDeviceSettings::GetBaudrateValueForEnum(CANBaudrate enumValue) {
bool IDeviceSettings::refresh(bool ignoreChecksum) {
if(disabled) {
err(APIError::SettingsNotAvailable);
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
@@ -140,12 +140,12 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) {
std::vector<uint8_t> rxSettings;
bool ret = com->getSettingsSync(rxSettings);
if(!ret) {
err(APIError::SettingsReadError);
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(rxSettings.size() < 6) { // We need to at least have the header of GLOBAL_SETTINGS
err(APIError::SettingsReadError);
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
@@ -158,17 +158,17 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) {
rxSettings.erase(rxSettings.begin(), rxSettings.begin() + gs_size);
if(gs_version != 5) {
err(APIError::SettingsVersionError);
report(APIEvent::Type::SettingsVersionError, APIEvent::Severity::Error);
return false;
}
if(rxLen != gs_len) {
err(APIError::SettingsLengthError);
report(APIEvent::Type::SettingsLengthError, APIEvent::Severity::Error);
return false;
}
if(!ignoreChecksum && gs_chksum != CalculateGSChecksum(rxSettings)) {
err(APIError::SettingsChecksumError);
report(APIEvent::Type::SettingsChecksumError, APIEvent::Severity::Error);
return false;
}
@@ -183,8 +183,20 @@ bool IDeviceSettings::refresh(bool ignoreChecksum) {
}
bool IDeviceSettings::apply(bool temporary) {
if(!settingsLoaded || disabled || readonly)
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
std::vector<uint8_t> bytestream;
bytestream.resize(7 + settings.size());
@@ -202,7 +214,11 @@ bool IDeviceSettings::apply(bool temporary) {
std::shared_ptr<Message> msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) { // We did not receive a response
refresh(); // Attempt to get the settings from the device so we're up to date if possible
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
return false;
}
@@ -217,7 +233,11 @@ bool IDeviceSettings::apply(bool temporary) {
com->sendCommand(Command::SetSettings, bytestream);
msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) {
refresh();
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
return false;
}
@@ -228,17 +248,32 @@ bool IDeviceSettings::apply(bool temporary) {
refresh(); // Refresh our buffer with what the device has, whether we were successful or not
return (msg && msg->data[0] == 1); // Device sends 0x01 for success
bool ret = (msg && msg->data[0] == 1); // Device sends 0x01 for success
if(!ret) {
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
}
return ret;
}
bool IDeviceSettings::applyDefaults(bool temporary) {
if(disabled || readonly)
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
com->sendCommand(Command::SetDefaultSettings);
std::shared_ptr<Message> msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) {
refresh();
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
return false;
}
@@ -263,7 +298,11 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
com->sendCommand(Command::SetSettings, bytestream);
msg = com->waitForMessageSync(std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000));
if(!msg || msg->data[0] != 1) {
refresh();
// Attempt to get the settings from the device so we're up to date if possible
if(refresh()) {
// refresh succeeded but previously there was an error
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
}
return false;
}
@@ -274,45 +313,79 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
refresh(); // Refresh our buffer with what the device has, whether we were successful or not
return (msg && msg->data[0] == 1); // Device sends 0x01 for success
bool ret = (msg && msg->data[0] == 1); // Device sends 0x01 for success
if(!ret) {
report(APIEvent::Type::FailedToWrite, APIEvent::Severity::Error);
}
return ret;
}
int64_t IDeviceSettings::getBaudrateFor(Network net) const {
if(!settingsLoaded || disabled)
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return -1;
}
switch(net.getType()) {
case Network::Type::CAN: {
const CAN_SETTINGS* cfg = getCANSettingsFor(net);
if(cfg == nullptr)
if(cfg == nullptr) {
report(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
int64_t baudrate = GetBaudrateValueForEnum((CANBaudrate)cfg->Baudrate);
if(baudrate == -1)
if(baudrate == -1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return -1;
}
return baudrate;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return -1;
}
}
bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
if(!settingsLoaded || disabled || readonly)
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
switch(net.getType()) {
case Network::Type::CAN: {
if(baudrate > 1000000) // This is an FD baudrate. Use setFDBaudrateFor instead.
if(baudrate > 1000000) { // This is an FD baudrate. Use setFDBaudrateFor instead.
report(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CAN_SETTINGS* cfg = getMutableCANSettingsFor(net);
if(cfg == nullptr)
if(cfg == nullptr) {
report(APIEvent::Type::CANSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1)
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return false;
}
cfg->Baudrate = (uint8_t)newBaud;
cfg->auto_baud = false;
cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values
@@ -320,12 +393,16 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
}
case Network::Type::LSFTCAN: {
CAN_SETTINGS* cfg = getMutableLSFTCANSettingsFor(net);
if(cfg == nullptr)
if(cfg == nullptr) {
report(APIEvent::Type::LSFTCANSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1)
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return false;
}
cfg->Baudrate = (uint8_t)newBaud;
cfg->auto_baud = false;
cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values
@@ -333,78 +410,127 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
}
case Network::Type::SWCAN: {
SWCAN_SETTINGS* cfg = getMutableSWCANSettingsFor(net);
if(cfg == nullptr)
if(cfg == nullptr) {
report(APIEvent::Type::SWCANSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1)
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return false;
}
cfg->Baudrate = (uint8_t)newBaud;
cfg->auto_baud = false;
cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values
return true;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
}
int64_t IDeviceSettings::getFDBaudrateFor(Network net) const {
if(!settingsLoaded || disabled)
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
}
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return -1;
}
switch(net.getType()) {
case Network::Type::CAN: {
const CANFD_SETTINGS* cfg = getCANFDSettingsFor(net);
if(cfg == nullptr)
if(cfg == nullptr) {
report(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::Error);
return -1;
}
int64_t baudrate = GetBaudrateValueForEnum((CANBaudrate)cfg->FDBaudrate);
if(baudrate == -1)
if(baudrate == -1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return -1;
}
return baudrate;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return -1;
}
}
bool IDeviceSettings::setFDBaudrateFor(Network net, int64_t baudrate) {
if(!settingsLoaded || disabled || readonly)
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
switch(net.getType()) {
case Network::Type::CAN: {
CANFD_SETTINGS* cfg = getMutableCANFDSettingsFor(net);
if(cfg == nullptr)
if(cfg == nullptr) {
report(APIEvent::Type::CANFDSettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
CANBaudrate newBaud = GetEnumValueForBaudrate(baudrate);
if(newBaud == (CANBaudrate)-1)
if(newBaud == (CANBaudrate)-1) {
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
return false;
}
cfg->FDBaudrate = (uint8_t)newBaud;
return true;
}
default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
}
template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure) {
if(!settingsLoaded || disabled || readonly)
if(!settingsLoaded) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false;
// This function is only called from C++ so the callers structure size and ours should never differ
if(sizeof(T) != structSize)
return false; // The wrong structure was passed in for the current device
}
if(disabled) {
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
return false;
}
if(readonly) {
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
return false;
}
// This function is only called from C++ so the caller's structure size and ours should never differ
if(sizeof(T) != structSize) {
report(APIEvent::Type::SettingsStructureMismatch, APIEvent::Severity::Error);
return false; // The wrong structure was passed in for the current device
}
size_t copySize = sizeof(T);
if(copySize > settings.size())
if(copySize > settings.size()) {
report(APIEvent::Type::SettingsStructureTruncated, APIEvent::Severity::EventWarning);
copySize = settings.size(); // TODO Warn user that their structure is truncated
// TODO Warn user that the device firmware doesn't support all the settings in the current API
//if(copySize < settings.size())
}
// Warn user that the device firmware doesn't support all the settings in the current API
if(copySize < settings.size())
report(APIEvent::Type::DeviceFirmwareOutOfDate, APIEvent::Severity::EventWarning);
memcpy(settings.data(), &newStructure, structSize);
return apply();
}
+102
View File
@@ -0,0 +1,102 @@
****************
**API Usage**
****************
API Concepts
================
Overview
~~~~~~~~~~~~~~~~~~~~
Events convey information about the API's inner workings to the user. There are 3 severity levels: ``EventInfo``, ``EventWarning``, and ``Error``.
**However, the API treats events of severities** ``EventInfo`` **and** ``EventWarning`` **differently than those of severity** ``Error`` **.**
From here on out, when we (and the API functions) refer to "events", we refer exclusively to those of severities ``EventInfo`` and ``EventWarning``, which use the events_ system.
Those of severity ``Error`` are referred to as "errors", which use a separate errors_ system.
Events should periodically be read out in order to avoid overflowing, and the last error should be read out immediately after an API function fails.
Additionally, `event callbacks`_ can be registered, which may remove the need to periodically read events in some cases.
.. _events:
Events
~~~~~~~~~~~~~~~~~~~~
The API stores events in a single buffer that can has a default size of 10,000 events.
This limit includes 1 reserved slot at the end of the buffer for a potential Event of type ``TooManyEvents`` and severity ``EventWarning``, which is added when there are too many events for the buffer to hold.
This could occur if the events aren't read out by the user often enough, or if the user sets the size of the buffer to a value smaller than the number of existing events.
There will only ever be one of these ``TooManyEvents`` events, and it will always be located at the very end of the buffer if it exists.
Because of this reserved slot, the buffer by default is able to hold 9,999 events. If capacity is exceeded, the oldest events in the buffer are automatically discarded until the buffer is exactly at capacity again.
When events are read out by the user, they are removed from the buffer. If an event filter is used, only the filtered events will be removed from the buffer.
In a multithreaded environment, all threads will log their events to the same buffer. In this case, the order of events will largely be meaningless, although the behavior of ``TooManyEvents`` is still guaranteed to be as described above.
.. _event callbacks:
Event Callbacks
~~~~~~~~~~~~~~~~~~~~
Users may register event callbacks, which are automatically called whenever a matching event is logged.
Message callbacks consist of a user-defined ``std::function< void( std::shared_ptr<APIEvent> ) >`` and optional EventFilter used for matching.
If no EventFilter is provided, the default-constructed one will be used, which matches any event.
Registering a callback returns an ``int`` representing the id of the callback, which should be stored by the user and later used to remove the callback when desired.
Note that this functionality is only available in C and C++. C does not currently support filters.
Event callbacks are run after the event has been added to the buffer of events. The buffer of events may be safely modified within the callback, such as getting (flushing) the type and severity of the triggering event.
Using event callbacks in this manner means that periodically reading events is unnecessary.
.. _errors:
Errors
~~~~~~~~~
The error system is threadsafe and separate from the events_ system.
Each thread keeps track of the last error logged on it, and getting the last error will return the last error from the calling thread, removing it in the process.
Trying to get the last error when there is none will return an event of type ``NoErrorFound`` and severity ``EventInfo``.
The API also contains some threads for internal use which may potentially log errors of their own and are inaccessible to the user.
These threads have been marked to downgrade any errors that occur on them to severity ``EventWarning`` and will log the corresponding event in the events_ system described above.
Device Concepts
================
Open/Close Status
~~~~~~~~~~~~~~~~~~~~~~~
In order to access device functionality, the device must first be opened, which begins communication between the API and the device.
The exception to this is setting the message polling status of the device.
Trying to open/close the device when the device is already open/closed will result in an error being logged on the calling thread.
Online/Offline Status
~~~~~~~~~~~~~~~~~~~~~~~
Going online begins communication between the device and the rest of the network. In order to be online, the device must also be open.
Trying to go online/offline when the device is already online/offline will result in an error being logged on the calling thread.
It is possible to have a device be both open and offline. In this situation, device settings such as the baudrate may still be read and changed.
This is useful for setting up your device properly before going online and joining the network.
Message Callbacks and Polling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to handle messages, users may register message callbacks, which are automatically called whenever a matching message is received.
Message callbacks consist of a user-defined ``std::function< void( std::shared_ptr<Message> ) >`` and optional message filter used for matching.
If no message filter is provided, the default-constructed one will be used, which matches any message.
Registering a callback returns an ``int`` representing the id of the callback, which should be stored by the user and later used to remove the callback when desired.
Note that this functionality is only available in C and C++. C does not currently support filters.
The default method of handling messages is to enable message polling, which is built upon message callbacks.
Enabling message polling will register a callback that stores each received message in a buffer for later retrieval.
The default limit of this buffer is 20,000 messages.
If the limit is exceeded, the oldest messages will be dropped until the buffer is at capacity, and an error will be logged on the calling thread.
To avoid exceeding the limit, try to get messages periodically, which will flush the buffer upon each call.
Attempting to read messages without first enabling message polling will result in an error being logged on the calling thread.
It is recommended to either enable message polling or manually register callbacks to handle messages, but not both.
Write Blocking Status
~~~~~~~~~~~~~~~~~~~~~~~
The write blocking status of the device determines the behavior of attempting to transmit to the device (likely via sending messages) with a large backlog of messages.
If write blocking is enabled, then the transmitting thread will wait for the entire buffer to be transmitted.
If write blocking is disabled, then the attempt to transmit will simply fail and an error will be logged on the calling thread.
+3 -3
View File
@@ -64,7 +64,7 @@ master_doc = 'index'
# General information about the project.
project = 'libicsneo'
copyright = '2018, Intrepid Control Systems, Inc'
copyright = '2019, Intrepid Control Systems, Inc'
author = 'Intrepid Control Systems, Inc.'
# The version info for the project you're documenting, acts as replacement for
@@ -72,9 +72,9 @@ author = 'Intrepid Control Systems, Inc.'
# built documents.
#
# The short X.Y version.
version = '0.1.0'
version = '0.2.0'
# The full version, including alpha/beta/rc tags.
release = '0.1.0 '
release = '0.2.0 '
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+1 -1
View File
@@ -64,7 +64,7 @@ master_doc = 'index'
# General information about the project.
project = 'libicsneo'
copyright = '2018, Intrepid Control Systems, Inc'
copyright = '2019, Intrepid Control Systems, Inc'
author = 'Intrepid Control Systems, Inc.'
# The version info for the project you're documenting, acts as replacement for
+1
View File
@@ -5,5 +5,6 @@ Welcome to libicsneo's documentation!
:maxdepth: 3
:caption: Documentation
Usage
icsneocpp
icsneoc
-127
View File
@@ -1,127 +0,0 @@
#ifndef __ICSNEO_API_ERROR_H_
#define __ICSNEO_API_ERROR_H_
#include <stdint.h>
#include <time.h>
typedef struct {
const char* description;
time_t timestamp;
uint32_t errorNumber;
uint8_t severity;
char serial[7];
uint8_t reserved[16];
} neoerror_t;
#ifdef __cplusplus
#include <vector>
#include <chrono>
#include <string>
#include <ostream>
namespace icsneo {
class Device;
class APIError {
public:
typedef std::chrono::system_clock ErrorClock;
typedef std::chrono::time_point<ErrorClock> ErrorTimePoint;
enum ErrorType : uint32_t {
Any = 0, // Used for filtering, should not appear in data
// API Errors
InvalidNeoDevice = 0x1000,
RequiredParameterNull = 0x1001,
BufferInsufficient = 0x1002,
OutputTruncated = 0x1003,
ParameterOutOfRange = 0x1004,
// Device Errors
PollingMessageOverflow = 0x2000,
NoSerialNumber = 0x2001,
IncorrectSerialNumber = 0x2002,
SettingsReadError = 0x2003,
SettingsVersionError = 0x2004,
SettingsLengthError = 0x2005,
SettingsChecksumError = 0x2006,
SettingsNotAvailable = 0x2007,
// Transport Errors
FailedToRead = 0x3000,
FailedToWrite = 0x3001,
DriverFailedToOpen = 0x3002,
PacketChecksumError = 0x3003,
TransmitBufferFull = 0x3004,
PCAPCouldNotStart = 0x3102,
PCAPCouldNotFindDevices = 0x3103,
TooManyErrors = 0xFFFFFFFE,
Unknown = 0xFFFFFFFF
};
enum class Severity : uint8_t {
Any = 0, // Used for filtering, should not appear in data
Info = 0x10,
Warning = 0x20,
Error = 0x30
};
APIError() : errorStruct({}), device(nullptr) {}
APIError(ErrorType error);
APIError(ErrorType error, const Device* device);
const neoerror_t* getNeoError() const noexcept { return &errorStruct; }
ErrorType getType() const noexcept { return ErrorType(errorStruct.errorNumber); }
Severity getSeverity() const noexcept { return Severity(errorStruct.severity); }
std::string getDescription() const noexcept { return std::string(errorStruct.description); }
const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide error
ErrorTimePoint getTimestamp() const noexcept { return timepoint; }
bool isForDevice(const Device* forDevice) const noexcept { return forDevice == device; }
bool isForDevice(std::string serial) const noexcept;
// As opposed to getDescription, this will also add text such as "neoVI FIRE 2 CY2468 Error: " to fully describe the problem
std::string describe() const noexcept;
friend std::ostream& operator<<(std::ostream& os, const APIError& error) {
os << error.describe();
return os;
}
static const char* DescriptionForType(ErrorType type);
static Severity SeverityForType(ErrorType type);
private:
neoerror_t errorStruct;
std::string serial;
ErrorTimePoint timepoint;
const Device* device;
void init(ErrorType error);
};
class ErrorFilter {
public:
ErrorFilter() {} // Empty filter matches anything
ErrorFilter(APIError::ErrorType error) : type(error) {}
ErrorFilter(APIError::Severity severity) : severity(severity) {}
ErrorFilter(const Device* device, APIError::ErrorType error = APIError::Any) : type(error), matchOnDevicePtr(true), device(device) {}
ErrorFilter(const Device* device, APIError::Severity severity) : severity(severity), matchOnDevicePtr(true), device(device) {}
ErrorFilter(std::string serial, APIError::ErrorType error = APIError::Any) : type(error), serial(serial) {}
ErrorFilter(std::string serial, APIError::Severity severity) : severity(severity), serial(serial) {}
bool match(const APIError& error) const noexcept;
APIError::Severity severity = APIError::Severity::Any;
APIError::ErrorType type = APIError::Any;
bool matchOnDevicePtr = false;
const Device* device = nullptr; // nullptr will match on "no device, generic API error"
std::string serial; // Empty serial will match any, including no device. Not affected by matchOnDevicePtr
};
}
#endif // __cplusplus
#endif
-98
View File
@@ -1,98 +0,0 @@
#ifndef __ICSNEO_API_ERRORMANAGER_H_
#define __ICSNEO_API_ERRORMANAGER_H_
#include <vector>
#include <list>
#include <mutex>
#include <functional>
#include "icsneo/api/error.h"
namespace icsneo {
typedef std::function<void (APIError::ErrorType)> device_errorhandler_t;
class ErrorManager {
public:
static ErrorManager& GetInstance();
size_t count(ErrorFilter filter = ErrorFilter()) const {
std::lock_guard<std::mutex> lk(mutex);
return count_internal(filter);
};
std::vector<APIError> get(ErrorFilter filter, size_t max = 0) { return get(max, filter); }
std::vector<APIError> get(size_t max = 0, ErrorFilter filter = ErrorFilter()) {
std::vector<APIError> ret;
get(ret, filter, max);
return ret;
}
void get(std::vector<APIError>& outErrors, ErrorFilter filter, size_t max = 0) { get(outErrors, max, filter); }
void get(std::vector<APIError>& outErrors, size_t max = 0, ErrorFilter filter = ErrorFilter());
bool getLastError(APIError& outErrors, ErrorFilter filter = ErrorFilter());
void add(APIError error) {
std::lock_guard<std::mutex> lk(mutex);
add_internal(error);
}
void add(APIError::ErrorType type) {
std::lock_guard<std::mutex> lk(mutex);
add_internal(type);
}
void add(APIError::ErrorType type, const Device* forDevice) {
std::lock_guard<std::mutex> lk(mutex);
add_internal(type, forDevice);
}
void discard(ErrorFilter filter = ErrorFilter());
void setErrorLimit(size_t newLimit) {
if(newLimit < 10) {
add(APIError::ParameterOutOfRange);
return;
}
std::lock_guard<std::mutex> lk(mutex);
errorLimit = newLimit;
enforceLimit();
}
size_t getErrorLimit() const { return errorLimit; }
private:
ErrorManager() {}
mutable std::mutex mutex;
std::list<APIError> errors;
size_t errorLimit = 10000;
size_t count_internal(ErrorFilter filter = ErrorFilter()) const;
void add_internal(APIError error) {
if(!beforeAddCheck(error.getType()))
return;
errors.push_back(error);
enforceLimit();
}
void add_internal(APIError::ErrorType type) {
if(!beforeAddCheck(type))
return;
errors.emplace_back(type);
enforceLimit();
}
void add_internal(APIError::ErrorType type, const Device* forDevice) {
if(!beforeAddCheck(type))
return;
errors.emplace_back(type, forDevice);
enforceLimit();
}
bool beforeAddCheck(APIError::ErrorType type); // Returns whether the error should be added
bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow
APIError::Severity lowestCurrentSeverity();
void discardLeastSevere(size_t count = 1);
};
}
#endif
+152
View File
@@ -0,0 +1,152 @@
#ifndef __ICSNEO_API_EVENT_H_
#define __ICSNEO_API_EVENT_H_
#include <stdint.h>
#include <time.h>
typedef struct {
const char* description;
time_t timestamp;
uint32_t eventNumber;
uint8_t severity;
char serial[7];
uint8_t reserved[16];
} neoevent_t;
#ifdef __cplusplus
#include <vector>
#include <chrono>
#include <string>
#include <ostream>
namespace icsneo {
class Device;
class APIEvent {
public:
typedef std::chrono::system_clock EventClock;
typedef std::chrono::time_point<EventClock> EventTimePoint;
enum class Type : uint32_t {
Any = 0, // Used for filtering, should not appear in data
// API Events
InvalidNeoDevice = 0x1000, // api
RequiredParameterNull = 0x1001,
BufferInsufficient = 0x1002,
OutputTruncated = 0x1003, // just a warning
ParameterOutOfRange = 0x1004,
DeviceCurrentlyOpen = 0x1005,
DeviceCurrentlyClosed = 0x1006,
DeviceCurrentlyOnline = 0x1007,
DeviceCurrentlyOffline = 0x1008,
DeviceCurrentlyPolling = 0x1009,
DeviceNotCurrentlyPolling = 0x1010,
UnsupportedTXNetwork = 0x1011,
MessageMaxLengthExceeded = 0x1012,
// Device Events
PollingMessageOverflow = 0x2000,
NoSerialNumber = 0x2001, // api
IncorrectSerialNumber = 0x2002, // api
SettingsReadError = 0x2003,
SettingsVersionError = 0x2004,
SettingsLengthError = 0x2005,
SettingsChecksumError = 0x2006,
SettingsNotAvailable = 0x2007,
SettingsReadOnly = 0x2008,
CANSettingsNotAvailable = 0x2009,
CANFDSettingsNotAvailable = 0x2010,
LSFTCANSettingsNotAvailable = 0x2011,
SWCANSettingsNotAvailable = 0x2012,
BaudrateNotFound = 0x2013,
UnexpectedNetworkType = 0x2014,
DeviceFirmwareOutOfDate = 0x2015,
SettingsStructureMismatch = 0x2016,
SettingsStructureTruncated = 0x2017,
NoDeviceResponse = 0x2018,
MessageFormattingError = 0x2019,
CANFDNotSupported = 0x2020,
RTRNotSupported = 0x2021,
// Transport Events
FailedToRead = 0x3000,
FailedToWrite = 0x3001,
DriverFailedToOpen = 0x3002,
DriverFailedToClose = 0x3003,
PacketChecksumError = 0x3004,
TransmitBufferFull = 0x3005,
PCAPCouldNotStart = 0x3102,
PCAPCouldNotFindDevices = 0x3103,
PacketDecodingError = 0x3104,
NoErrorFound = 0xFFFFFFFD,
TooManyEvents = 0xFFFFFFFE,
Unknown = 0xFFFFFFFF
};
enum class Severity : uint8_t {
Any = 0, // Used for filtering, should not appear in data
EventInfo = 0x10,
EventWarning = 0x20,
Error = 0x30
};
APIEvent() : eventStruct({}), serial(), timepoint(), device(nullptr) {}
APIEvent(APIEvent::Type event, APIEvent::Severity severity, const Device* device = nullptr);
const neoevent_t* getNeoEvent() const noexcept { return &eventStruct; }
Type getType() const noexcept { return Type(eventStruct.eventNumber); }
Severity getSeverity() const noexcept { return Severity(eventStruct.severity); }
std::string getDescription() const noexcept { return std::string(eventStruct.description); }
const Device* getDevice() const noexcept { return device; } // Will return nullptr if this is an API-wide event
EventTimePoint getTimestamp() const noexcept { return timepoint; }
void downgradeFromError() noexcept;
bool isForDevice(const Device* forDevice) const noexcept { return forDevice == device; }
bool isForDevice(std::string serial) const noexcept;
// As opposed to getDescription, this will also add text such as "neoVI FIRE 2 CY2468 Error: " to fully describe the problem
std::string describe() const noexcept;
friend std::ostream& operator<<(std::ostream& os, const APIEvent& event) {
os << event.describe();
return os;
}
static const char* DescriptionForType(Type type);
private:
neoevent_t eventStruct;
std::string serial;
EventTimePoint timepoint;
const Device* device;
void init(APIEvent::Type event, APIEvent::Severity);
};
class EventFilter {
public:
EventFilter() {} // Empty filter matches anything
EventFilter(APIEvent::Type type, APIEvent::Severity severity = APIEvent::Severity::Any) : type(type), severity(severity) {}
EventFilter(APIEvent::Severity severity) : severity(severity) {}
EventFilter(const Device* device, APIEvent::Type type = APIEvent::Type::Any, APIEvent::Severity severity = APIEvent::Severity::Any) : type(type), severity(severity), matchOnDevicePtr(true), device(device) {}
EventFilter(const Device* device, APIEvent::Severity severity) : severity(severity), matchOnDevicePtr(true), device(device) {}
EventFilter(std::string serial, APIEvent::Type type = APIEvent::Type::Any, APIEvent::Severity severity = APIEvent::Severity::Any) : type(type), severity(severity), serial(serial) {}
EventFilter(std::string serial, APIEvent::Severity severity) : severity(severity), serial(serial) {}
bool match(const APIEvent& event) const noexcept;
APIEvent::Type type = APIEvent::Type::Any;
APIEvent::Severity severity = APIEvent::Severity::Any;
bool matchOnDevicePtr = false;
const Device* device = nullptr; // nullptr will match on "no device, generic API event"
std::string serial; // Empty serial will match any, including no device. Not affected by matchOnDevicePtr
};
}
#endif // __cplusplus
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef __EVENTCALLBACK_H_
#define __EVENTCALLBACK_H_
#include <functional>
#include <memory>
#include "event.h"
namespace icsneo {
class EventCallback {
public:
typedef std::function< void( std::shared_ptr<APIEvent> ) > fn_eventCallback;
EventCallback(fn_eventCallback cb, std::shared_ptr<EventFilter> f) : callback(cb), filter(f) {}
EventCallback(fn_eventCallback cb, EventFilter f = EventFilter()) : callback(cb), filter(std::make_shared<EventFilter>(f)) {}
// Allow the filter to be placed first if the user wants (maybe in the case of a lambda)
EventCallback(std::shared_ptr<EventFilter> f, fn_eventCallback cb) : callback(cb), filter(f) {}
EventCallback(EventFilter f, fn_eventCallback cb) : callback(cb), filter(std::make_shared<EventFilter>(f)) {}
virtual bool callIfMatch(const std::shared_ptr<APIEvent>& event) const {
bool ret = filter->match(*event);
if(ret)
callback(event);
return ret;
}
const EventFilter& getFilter() const { return *filter; }
const fn_eventCallback& getCallback() const { return callback; }
private:
fn_eventCallback callback;
std::shared_ptr<EventFilter> filter;
};
}
#endif
+209
View File
@@ -0,0 +1,209 @@
#ifndef __ICSNEO_API_EVENTMANAGER_H_
#define __ICSNEO_API_EVENTMANAGER_H_
#include <vector>
#include <list>
#include <mutex>
#include <functional>
#include<map>
#include <thread>
#include <algorithm>
#include "icsneo/api/event.h"
#include "icsneo/api/eventcallback.h"
namespace icsneo {
typedef std::function<void (APIEvent::Type, APIEvent::Severity)> device_eventhandler_t;
class EventManager {
public:
~EventManager() {
destructing = true;
}
static EventManager& GetInstance();
void ResetInstance();
// If this thread is not in the map, add it to be ignored
// If it is, set it to be ignored
void downgradeErrorsOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = true;
} else {
downgradedThreads.insert({std::this_thread::get_id(), true});
}
}
// If this thread exists in the map, turn off downgrading
void cancelErrorDowngradingOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = false;
}
}
bool isDowngradingErrorsOnCurrentThread() const;
int addEventCallback(const EventCallback &cb);
bool removeEventCallback(int id);
size_t eventCount(EventFilter filter = EventFilter()) const {
std::lock_guard<std::mutex> lk(eventsMutex);
return count_internal(filter);
};
std::vector<APIEvent> get(EventFilter filter, size_t max = 0) { return get(max, filter); }
std::vector<APIEvent> get(size_t max = 0, EventFilter filter = EventFilter()) {
std::vector<APIEvent> ret;
get(ret, filter, max);
return ret;
}
void get(std::vector<APIEvent>& outEvents, EventFilter filter, size_t max = 0) { get(outEvents, max, filter); }
void get(std::vector<APIEvent>& outEvents, size_t max = 0, EventFilter filter = EventFilter());
APIEvent getLastError();
void add(APIEvent event) {
if(destructing)
return;
if(event.getSeverity() == APIEvent::Severity::Error) {
// if the error was added on a thread that downgrades errors (non-user thread)
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end() && i->second) {
event.downgradeFromError();
std::unique_lock<std::mutex> eventsLock(eventsMutex);
add_internal_event(event);
// free the lock so that callbacks may modify events
eventsLock.unlock();
runCallbacks(event);
} else {
std::lock_guard<std::mutex> errorsLock(errorsMutex);
add_internal_error(event);
}
} else {
std::unique_lock<std::mutex> eventsLock(eventsMutex);
add_internal_event(event);
// free the lock so that callbacks may modify events
eventsLock.unlock();
runCallbacks(event);
}
}
void add(APIEvent::Type type, APIEvent::Severity severity, const Device* forDevice = nullptr) {
add(APIEvent(type, severity, forDevice));
}
void discard(EventFilter filter = EventFilter());
void setEventLimit(size_t newLimit) {
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
if(newLimit == eventLimit)
return;
if(newLimit < 10) {
add(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return;
}
eventLimit = newLimit;
std::lock_guard<std::mutex> eventsLock(eventsMutex);
if(enforceLimit())
add_internal_event(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
}
size_t getEventLimit() const {
std::lock_guard<std::mutex> lk(eventLimitMutex);
return eventLimit;
}
private:
EventManager() : eventsMutex(), errorsMutex(), downgradedThreadsMutex(), callbacksMutex(), callbackIDMutex(), eventLimitMutex(), downgradedThreads(), callbacks(), events(), lastUserErrors(), eventLimit(10000) {}
EventManager(const EventManager &other);
EventManager& operator=(const EventManager &other);
// Used by functions for threadsafety
mutable std::mutex eventsMutex;
mutable std::mutex errorsMutex;
mutable std::mutex downgradedThreadsMutex;
mutable std::mutex callbacksMutex;
mutable std::mutex callbackIDMutex;
mutable std::mutex eventLimitMutex;
std::map<std::thread::id, bool> downgradedThreads;
std::map<int, EventCallback> callbacks;
int callbackID = 0;
bool destructing = false;
// Stores all events
std::list<APIEvent> events;
std::map<std::thread::id, APIEvent> lastUserErrors;
size_t eventLimit = 10000;
size_t count_internal(EventFilter filter = EventFilter()) const;
void runCallbacks(APIEvent event) {
std::lock_guard<std::mutex> lk(callbacksMutex);
for(auto &i : callbacks) {
i.second.callIfMatch(std::make_shared<APIEvent>(event));
}
}
/**
* Places a {id, event} pair into the lastUserErrors
* If the key id already exists in the map, replace the event of that pair with the new one
*/
void add_internal_error(APIEvent event) {
std::thread::id id = std::this_thread::get_id();
auto it = lastUserErrors.find(id);
if(it == lastUserErrors.end())
lastUserErrors.insert({id, event});
else
it->second = event;
}
/**
* If events is not full, add the event at the end
* Otherwise, remove the oldest event, push the event to the back and push a APIEvent::TooManyEvents to the back (in that order)
*/
void add_internal_event(APIEvent event) {
// Ensure the event list is at most exactly full (size of eventLimit - 1, leaving room for a potential APIEvent::TooManyEvents)
// Removes any events of type TooManyEvents from the end before checking to avoid duplicates.
enforceLimit();
// We are exactly full, either because the list was truncated or because we were simply full before
if(events.size() == eventLimit - 1) {
// If the event is worth adding
if(event.getType() != APIEvent::Type::TooManyEvents) {
discardOldest(1);
events.push_back(event);
}
events.push_back(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
} else {
if (event.getType() != APIEvent::Type::TooManyEvents)
events.push_back(event);
}
}
bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow
void discardOldest(size_t count = 1);
};
}
#endif
+4 -1
View File
@@ -10,7 +10,10 @@ enum class Command : uint8_t {
//GetSettings = 0xA5, // Previously known as RED_CMD_READ_BAUD_REQ, now unused
SaveSettings = 0xA6,
SetDefaultSettings = 0xA8, // Follow up with SaveSettings to write to EEPROM
ReadSettings = 0xC7 // Previously known as 3G_READ_SETTINGS_EX
RequestStatusUpdate = 0xBC,
ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX
UpdateLEDState = 0xA7,
FlexRayControl = 0xF3
};
}
+10 -6
View File
@@ -7,7 +7,7 @@
#include "icsneo/communication/packet.h"
#include "icsneo/communication/message/callback/messagecallback.h"
#include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/decoder.h"
@@ -23,20 +23,23 @@ namespace icsneo {
class Communication {
public:
Communication(
device_errorhandler_t err,
device_eventhandler_t report,
std::unique_ptr<ICommunication> com,
std::shared_ptr<Packetizer> p,
std::unique_ptr<Encoder> e,
std::unique_ptr<Decoder> md) : packetizer(p), encoder(std::move(e)), decoder(std::move(md)), err(err), impl(std::move(com)) {}
std::unique_ptr<Decoder> md) : packetizer(p), encoder(std::move(e)), decoder(std::move(md)), report(report), impl(std::move(com)) {}
virtual ~Communication() { close(); }
bool open();
bool close();
bool isOpen();
virtual void spawnThreads();
virtual void joinThreads();
bool rawWrite(const std::vector<uint8_t>& bytes) { return impl->write(bytes); }
virtual bool sendPacket(std::vector<uint8_t>& bytes);
void setWriteBlocks(bool blocks) { impl->writeBlocks = blocks; }
virtual bool sendCommand(Command cmd, bool boolean) { return sendCommand(cmd, std::vector<uint8_t>({ (uint8_t)boolean })); }
virtual bool sendCommand(Command cmd, std::vector<uint8_t> arguments = {});
bool getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
@@ -52,17 +55,18 @@ public:
std::shared_ptr<Packetizer> packetizer; // Ownership is shared with the encoder
std::unique_ptr<Encoder> encoder;
std::unique_ptr<Decoder> decoder;
device_errorhandler_t err;
device_eventhandler_t report;
protected:
std::unique_ptr<ICommunication> impl;
static int messageCallbackIDCounter;
std::mutex messageCallbacksLock;
std::map<int, MessageCallback> messageCallbacks;
std::atomic<bool> closing{false};
private:
bool isOpen = false;
void dispatchMessage(const std::shared_ptr<Message>& msg);
private:
std::thread readTaskThread;
void readTask();
};
+3 -3
View File
@@ -5,7 +5,7 @@
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/packet.h"
#include "icsneo/communication/network.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include <queue>
#include <vector>
#include <memory>
@@ -16,13 +16,13 @@ class Decoder {
public:
static uint64_t GetUInt64FromLEBytes(uint8_t* bytes);
Decoder(device_errorhandler_t err) : err(err) {}
Decoder(device_eventhandler_t report) : report(report) {}
bool decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet);
uint16_t timestampResolution = 25;
private:
device_errorhandler_t err;
device_eventhandler_t report;
#pragma pack(push, 1)
+2 -2
View File
@@ -15,7 +15,7 @@ namespace icsneo {
class Encoder {
public:
Encoder(device_errorhandler_t err, std::shared_ptr<Packetizer> p) : packetizer(p), err(err) {}
Encoder(device_eventhandler_t report, std::shared_ptr<Packetizer> p) : packetizer(p), report(report) {}
bool encode(std::vector<uint8_t>& result, const std::shared_ptr<Message>& message);
bool encode(std::vector<uint8_t>& result, Command cmd, bool boolean) { return encode(result, cmd, std::vector<uint8_t>({ (uint8_t)boolean })); }
bool encode(std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments = {});
@@ -23,7 +23,7 @@ public:
bool supportCANFD = false;
private:
std::shared_ptr<Packetizer> packetizer;
device_errorhandler_t err;
device_eventhandler_t report;
};
}
@@ -7,14 +7,14 @@
#include <thread>
#include <mutex>
#include <condition_variable>
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/third-party/concurrentqueue/blockingconcurrentqueue.h"
namespace icsneo {
class ICommunication {
public:
ICommunication(const device_errorhandler_t& handler) : err(handler) {}
ICommunication(const device_eventhandler_t& handler) : report(handler) {}
virtual ~ICommunication() {}
virtual bool open() = 0;
virtual bool isOpen() = 0;
@@ -27,7 +27,7 @@ public:
writeCV.notify_one();
}
device_errorhandler_t err;
device_eventhandler_t report;
size_t writeQueueSize = 50;
bool writeBlocks = true; // Otherwise it just fails when the queue is full
@@ -0,0 +1,35 @@
#ifndef __FLEXRAYCONTROLMESSAGE_H_
#define __FLEXRAYCONTROLMESSAGE_H_
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/packet.h"
#include "icsneo/device/extensions/flexray/opcode.h"
#include "icsneo/device/extensions/flexray/pocstatus.h"
namespace icsneo {
// Internal message which gives us the state of the FlexRay Controllers
class FlexRayControlMessage : public Message {
public:
static std::vector<uint8_t> BuildBaseControlArgs(uint8_t controller, FlexRay::Opcode op, std::initializer_list<uint8_t> args);
static std::vector<uint8_t> BuildReadCCRegsArgs(uint8_t controller, uint16_t startAddress, uint8_t numRegisters = 1);
static std::vector<uint8_t> BuildWriteCCRegArgs(uint8_t controller, uint16_t address, uint32_t value);
FlexRayControlMessage(const Packet& packet);
virtual ~FlexRayControlMessage() = default;
bool decoded = false;
uint8_t controller = 0xff; // Controller index, either 0 or 1
FlexRay::Opcode opcode = FlexRay::Opcode::Unknown;
FlexRay::POCStatus pocStatus = FlexRay::POCStatus::Unknown;
uint16_t slotCounterA = 0;
uint16_t slotCounterB = 0;
uint16_t macroTick = 0;
uint16_t cycleCount = 0;
uint32_t rateCorrection = 0;
uint32_t offsetCorrection = 0;
std::vector<uint32_t> registers;
};
}
#endif
@@ -0,0 +1,32 @@
#ifndef __FLEXRAYMESSAGE_H_
#define __FLEXRAYMESSAGE_H_
#include "icsneo/communication/message/message.h"
#include "icsneo/device/extensions/flexray/symbol.h"
#include "icsneo/device/extensions/flexray/crcstatus.h"
namespace icsneo {
class FlexRayMessage : public Message {
public:
uint16_t slotid = 0;
double tsslen = 0;
double framelen = 0;
FlexRay::Symbol symbol = FlexRay::Symbol::None;
FlexRay::CRCStatus headerCRCStatus = FlexRay::CRCStatus::OK;
uint16_t headerCRC = 0;
FlexRay::CRCStatus crcStatus = FlexRay::CRCStatus::OK;
uint32_t frameCRC = 0;
bool channelB = false;
bool nullFrame = false;
bool reserved0was1 = false;
bool payloadPreamble = false;
bool sync = false;
bool startup = false;
bool dynamic = false;
uint8_t cycle = 0;
};
}
#endif
@@ -11,7 +11,7 @@ namespace icsneo {
class MultiChannelCommunication : public Communication {
public:
MultiChannelCommunication(
device_errorhandler_t err,
device_eventhandler_t err,
std::unique_ptr<ICommunication> com,
std::shared_ptr<Packetizer> p,
std::unique_ptr<Encoder> e,
@@ -44,6 +44,62 @@ private:
HostPC_to_Microblaze = 0x80, // Host PC data to microblaze processor
Microblaze_to_HostPC = 0x81 // Microblaze processor data to host PC
};
static bool FixSlaveVNETPacketNetID(Packet& packet);
enum class CoreMiniNetwork : uint8_t {
HSCAN1 = (0),
MSCAN1 = (1),
LIN1 = (2),
LIN2 = (3),
VIRTUAL = (4),
HSCAN2 = (5),
LSFTCAN1 = (6),
SWCAN1 = (7),
HSCAN3 = (8),
GMCGI = (9),
J1850_VPW = (10),
LIN3 = (11),
LIN4 = (12),
J1708 = (13),
HSCAN4 = (14),
HSCAN5 = (15),
KLINE1 = (16),
KLINE2 = (17),
KLINE3 = (18),
KLINE4 = (19),
FLEXRAY_1A = (20),
UART = (21),
UART2 = (22),
LIN5 = (23),
MOST25 = (24),
MOST50 = (25),
FLEXRAY_1B = (26),
SWCAN2 = (27),
ETHERNET_DAQ = (28),
ETHERNET = (29),
FLEXRAY_2A = (30),
FLEXRAY_2B = (31),
HSCAN6 = (32),
HSCAN7 = (33),
LIN6 = (34),
LSFTCAN2 = (35),
OP_ETHERNET1 = (36),
OP_ETHERNET2 = (37),
OP_ETHERNET3 = (38),
OP_ETHERNET4 = (39),
OP_ETHERNET5 = (40),
OP_ETHERNET6 = (41),
OP_ETHERNET7 = (42),
OP_ETHERNET8 = (43),
OP_ETHERNET9 = (44),
OP_ETHERNET10 = (45),
OP_ETHERNET11 = (46),
OP_ETHERNET12 = (47),
KLINE5 = (48),
KLINE6 = (49),
FLEXRAY1 = (50),
FLEXRAY2 = (51)
};
static bool CommandTypeIsValid(CommandType cmd) {
switch(cmd) {
case CommandType::PlasmaReadRequest:
+116 -111
View File
@@ -112,6 +112,7 @@ public:
HSCAN7 = 97,
LIN6 = 98,
LSFTCAN2 = 99,
FlexRayControl = 243,
HW_COM_Latency_Test = 512,
Device_Status = 513,
Any = 0xfffe, // Never actually set as type, but used as flag for filtering
@@ -187,6 +188,7 @@ public:
case NetID::RED:
case NetID::Reset_Status:
case NetID::Device_Status:
case NetID::FlexRayControl:
return Type::Internal;
case NetID::Invalid:
case NetID::Any:
@@ -408,14 +410,17 @@ public:
return "LIN 6";
case NetID::LSFTCAN2:
return "LSFTCAN 2";
case NetID::FlexRayControl:
return "FlexRay Control";
case NetID::HW_COM_Latency_Test:
return "HW COM Latency Test";
case NetID::Device_Status:
return "Device Status";
case NetID::Any:
case NetID::Invalid:
default:
return "Invalid Network";
break;
}
return "Invalid Network";
}
Network() { setValue(NetID::Invalid); }
@@ -443,121 +448,121 @@ private:
#endif
#ifdef __ICSNEOC_H_
#define ICSNEO_NETID_DEVICE ((uint16_t)0)
#define ICSNEO_NETID_HSCAN ((uint16_t)1)
#define ICSNEO_NETID_MSCAN ((uint16_t)2)
#define ICSNEO_NETID_SWCAN ((uint16_t)3)
#define ICSNEO_NETID_LSFTCAN ((uint16_t)4)
#define ICSNEO_NETID_FORDSCP ((uint16_t)5)
#define ICSNEO_NETID_J1708 ((uint16_t)6)
#define ICSNEO_NETID_AUX ((uint16_t)7)
#define ICSNEO_NETID_J1850VPW ((uint16_t)8)
#define ICSNEO_NETID_ISO ((uint16_t)9)
#define ICSNEO_NETID_ISOPIC ((uint16_t)10)
#define ICSNEO_NETID_MAIN51 ((uint16_t)11)
#define ICSNEO_NETID_RED ((uint16_t)12)
#define ICSNEO_NETID_SCI ((uint16_t)13)
#define ICSNEO_NETID_ISO2 ((uint16_t)14)
#define ICSNEO_NETID_ISO14230 ((uint16_t)15)
#define ICSNEO_NETID_LIN ((uint16_t)16)
#define ICSNEO_NETID_OP_ETHERNET1 ((uint16_t)17)
#define ICSNEO_NETID_OP_ETHERNET2 ((uint16_t)18)
#define ICSNEO_NETID_OP_ETHERNET3 ((uint16_t)19)
#define ICSNEO_NETID_DEVICE 0
#define ICSNEO_NETID_HSCAN 1
#define ICSNEO_NETID_MSCAN 2
#define ICSNEO_NETID_SWCAN 3
#define ICSNEO_NETID_LSFTCAN 4
#define ICSNEO_NETID_FORDSCP 5
#define ICSNEO_NETID_J1708 6
#define ICSNEO_NETID_AUX 7
#define ICSNEO_NETID_J1850VPW 8
#define ICSNEO_NETID_ISO 9
#define ICSNEO_NETID_ISOPIC 10
#define ICSNEO_NETID_MAIN51 11
#define ICSNEO_NETID_RED 12
#define ICSNEO_NETID_SCI 13
#define ICSNEO_NETID_ISO2 14
#define ICSNEO_NETID_ISO14230 15
#define ICSNEO_NETID_LIN 16
#define ICSNEO_NETID_OP_ETHERNET1 17
#define ICSNEO_NETID_OP_ETHERNET2 18
#define ICSNEO_NETID_OP_ETHERNET3 19
// START Device Command Returns
// When we send a command, the device returns on one of these, depending on command
#define ICSNEO_NETID_RED_EXT_MEMORYREAD ((uint16_t)20)
#define ICSNEO_NETID_RED_INT_MEMORYREAD ((uint16_t)21)
#define ICSNEO_NETID_RED_DFLASH_READ ((uint16_t)22)
#define ICSNEO_NETID_RED_SDCARD_READ ((uint16_t)23)
#define ICSNEO_NETID_CAN_ERRBITS ((uint16_t)24)
#define ICSNEO_NETID_RED_DFLASH_WRITE_DONE ((uint16_t)25)
#define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL ((uint16_t)26)
#define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL ((uint16_t)27)
#define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL ((uint16_t)28)
#define ICSNEO_NETID_RED_WAVE_LIN2_LOGICAL ((uint16_t)29)
#define ICSNEO_NETID_RED_WAVE_LIN1_ANALOG ((uint16_t)30)
#define ICSNEO_NETID_RED_WAVE_LIN2_ANALOG ((uint16_t)31)
#define ICSNEO_NETID_RED_WAVE_MISC_ANALOG ((uint16_t)32)
#define ICSNEO_NETID_RED_WAVE_MISCDIO2_LOGICAL ((uint16_t)33)
#define ICSNEO_NETID_RED_NETWORK_COM_ENABLE_EX ((uint16_t)34)
#define ICSNEO_NETID_RED_NEOVI_NETWORK ((uint16_t)35)
#define ICSNEO_NETID_RED_READ_BAUD_SETTINGS ((uint16_t)36)
#define ICSNEO_NETID_RED_OLDFORMAT ((uint16_t)37)
#define ICSNEO_NETID_RED_SCOPE_CAPTURE ((uint16_t)38)
#define ICSNEO_NETID_RED_HARDWARE_EXCEP ((uint16_t)39)
#define ICSNEO_NETID_RED_GET_RTC ((uint16_t)40)
#define ICSNEO_NETID_RED_EXT_MEMORYREAD 20
#define ICSNEO_NETID_RED_INT_MEMORYREAD 21
#define ICSNEO_NETID_RED_DFLASH_READ 22
#define ICSNEO_NETID_RED_SDCARD_READ 23
#define ICSNEO_NETID_CAN_ERRBITS 24
#define ICSNEO_NETID_RED_DFLASH_WRITE_DONE 25
#define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL 26
#define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL 27
#define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL 28
#define ICSNEO_NETID_RED_WAVE_LIN2_LOGICAL 29
#define ICSNEO_NETID_RED_WAVE_LIN1_ANALOG 30
#define ICSNEO_NETID_RED_WAVE_LIN2_ANALOG 31
#define ICSNEO_NETID_RED_WAVE_MISC_ANALOG 32
#define ICSNEO_NETID_RED_WAVE_MISCDIO2_LOGICAL 33
#define ICSNEO_NETID_RED_NETWORK_COM_ENABLE_EX 34
#define ICSNEO_NETID_RED_NEOVI_NETWORK 35
#define ICSNEO_NETID_RED_READ_BAUD_SETTINGS 36
#define ICSNEO_NETID_RED_OLDFORMAT 37
#define ICSNEO_NETID_RED_SCOPE_CAPTURE 38
#define ICSNEO_NETID_RED_HARDWARE_EXCEP 39
#define ICSNEO_NETID_RED_GET_RTC 40
// END Device Command Returns
#define ICSNEO_NETID_ISO3 ((uint16_t)41)
#define ICSNEO_NETID_HSCAN2 ((uint16_t)42)
#define ICSNEO_NETID_HSCAN3 ((uint16_t)44)
#define ICSNEO_NETID_OP_ETHERNET4 ((uint16_t)45)
#define ICSNEO_NETID_OP_ETHERNET5 ((uint16_t)46)
#define ICSNEO_NETID_ISO4 ((uint16_t)47)
#define ICSNEO_NETID_LIN2 ((uint16_t)48)
#define ICSNEO_NETID_LIN3 ((uint16_t)49)
#define ICSNEO_NETID_LIN4 ((uint16_t)50)
//#define ICSNEO_NETID_MOST ((uint16_t)51) Old and unused
#define ICSNEO_NETID_RED_APP_ERROR ((uint16_t)52)
#define ICSNEO_NETID_CGI ((uint16_t)53)
#define ICSNEO_NETID_RESET_STATUS ((uint16_t)54)
#define ICSNEO_NETID_FB_STATUS ((uint16_t)55)
#define ICSNEO_NETID_APP_SIGNAL_STATUS ((uint16_t)56)
#define ICSNEO_NETID_READ_DATALINK_CM_TX_MSG ((uint16_t)57)
#define ICSNEO_NETID_READ_DATALINK_CM_RX_MSG ((uint16_t)58)
#define ICSNEO_NETID_LOGGING_OVERFLOW ((uint16_t)59)
#define ICSNEO_NETID_READ_SETTINGS ((uint16_t)60)
#define ICSNEO_NETID_HSCAN4 ((uint16_t)61)
#define ICSNEO_NETID_HSCAN5 ((uint16_t)62)
#define ICSNEO_NETID_RS232 ((uint16_t)63)
#define ICSNEO_NETID_UART ((uint16_t)64)
#define ICSNEO_NETID_UART2 ((uint16_t)65)
#define ICSNEO_NETID_UART3 ((uint16_t)66)
#define ICSNEO_NETID_UART4 ((uint16_t)67)
#define ICSNEO_NETID_SWCAN2 ((uint16_t)68)
#define ICSNEO_NETID_ETHERNET_DAQ ((uint16_t)69)
#define ICSNEO_NETID_DATA_TO_HOST ((uint16_t)70)
#define ICSNEO_NETID_TEXTAPI_TO_HOST ((uint16_t)71)
#define ICSNEO_NETID_OP_ETHERNET6 ((uint16_t)73)
#define ICSNEO_NETID_RED_VBAT ((uint16_t)74)
#define ICSNEO_NETID_OP_ETHERNET7 ((uint16_t)75)
#define ICSNEO_NETID_OP_ETHERNET8 ((uint16_t)76)
#define ICSNEO_NETID_OP_ETHERNET9 ((uint16_t)77)
#define ICSNEO_NETID_OP_ETHERNET10 ((uint16_t)78)
#define ICSNEO_NETID_OP_ETHERNET11 ((uint16_t)79)
#define ICSNEO_NETID_FLEXRAY1A ((uint16_t)80)
#define ICSNEO_NETID_FLEXRAY1B ((uint16_t)81)
#define ICSNEO_NETID_FLEXRAY2A ((uint16_t)82)
#define ICSNEO_NETID_FLEXRAY2B ((uint16_t)83)
#define ICSNEO_NETID_LIN5 ((uint16_t)84)
#define ICSNEO_NETID_FLEXRAY ((uint16_t)85)
#define ICSNEO_NETID_FLEXRAY2 ((uint16_t)86)
#define ICSNEO_NETID_OP_ETHERNET12 ((uint16_t)87)
#define ICSNEO_NETID_MOST25 ((uint16_t)90)
#define ICSNEO_NETID_MOST50 ((uint16_t)91)
#define ICSNEO_NETID_MOST150 ((uint16_t)92)
#define ICSNEO_NETID_ETHERNET ((uint16_t)93)
#define ICSNEO_NETID_GMFSA ((uint16_t)94)
#define ICSNEO_NETID_TCP ((uint16_t)95)
#define ICSNEO_NETID_HSCAN6 ((uint16_t)96)
#define ICSNEO_NETID_HSCAN7 ((uint16_t)97)
#define ICSNEO_NETID_LIN6 ((uint16_t)98)
#define ICSNEO_NETID_LSFTCAN2 ((uint16_t)99)
#define ICSNEO_NETID_HW_COM_LATENCY_TEST ((uint16_t)512)
#define ICSNEO_NETID_DEVICE_STATUS ((uint16_t)513)
#define ICSNEO_NETID_ANY ((uint16_t)0xfffe) // Never actually set as type, but used as flag for filtering
#define ICSNEO_NETID_INVALID ((uint16_t)0xffff)
#define ICSNEO_NETID_ISO3 41
#define ICSNEO_NETID_HSCAN2 42
#define ICSNEO_NETID_HSCAN3 44
#define ICSNEO_NETID_OP_ETHERNET4 45
#define ICSNEO_NETID_OP_ETHERNET5 46
#define ICSNEO_NETID_ISO4 47
#define ICSNEO_NETID_LIN2 48
#define ICSNEO_NETID_LIN3 49
#define ICSNEO_NETID_LIN4 50
//#define ICSNEO_NETID_MOST 51 Old and unused
#define ICSNEO_NETID_RED_APP_ERROR 52
#define ICSNEO_NETID_CGI 53
#define ICSNEO_NETID_RESET_STATUS 54
#define ICSNEO_NETID_FB_STATUS 55
#define ICSNEO_NETID_APP_SIGNAL_STATUS 56
#define ICSNEO_NETID_READ_DATALINK_CM_TX_MSG 57
#define ICSNEO_NETID_READ_DATALINK_CM_RX_MSG 58
#define ICSNEO_NETID_LOGGING_OVERFLOW 59
#define ICSNEO_NETID_READ_SETTINGS 60
#define ICSNEO_NETID_HSCAN4 61
#define ICSNEO_NETID_HSCAN5 62
#define ICSNEO_NETID_RS232 63
#define ICSNEO_NETID_UART 64
#define ICSNEO_NETID_UART2 65
#define ICSNEO_NETID_UART3 66
#define ICSNEO_NETID_UART4 67
#define ICSNEO_NETID_SWCAN2 68
#define ICSNEO_NETID_ETHERNET_DAQ 69
#define ICSNEO_NETID_DATA_TO_HOST 70
#define ICSNEO_NETID_TEXTAPI_TO_HOST 71
#define ICSNEO_NETID_OP_ETHERNET6 73
#define ICSNEO_NETID_RED_VBAT 74
#define ICSNEO_NETID_OP_ETHERNET7 75
#define ICSNEO_NETID_OP_ETHERNET8 76
#define ICSNEO_NETID_OP_ETHERNET9 77
#define ICSNEO_NETID_OP_ETHERNET10 78
#define ICSNEO_NETID_OP_ETHERNET11 79
#define ICSNEO_NETID_FLEXRAY1A 80
#define ICSNEO_NETID_FLEXRAY1B 81
#define ICSNEO_NETID_FLEXRAY2A 82
#define ICSNEO_NETID_FLEXRAY2B 83
#define ICSNEO_NETID_LIN5 84
#define ICSNEO_NETID_FLEXRAY 85
#define ICSNEO_NETID_FLEXRAY2 86
#define ICSNEO_NETID_OP_ETHERNET12 87
#define ICSNEO_NETID_MOST25 90
#define ICSNEO_NETID_MOST50 91
#define ICSNEO_NETID_MOST150 92
#define ICSNEO_NETID_ETHERNET 93
#define ICSNEO_NETID_GMFSA 94
#define ICSNEO_NETID_TCP 95
#define ICSNEO_NETID_HSCAN6 96
#define ICSNEO_NETID_HSCAN7 97
#define ICSNEO_NETID_LIN6 98
#define ICSNEO_NETID_LSFTCAN2 99
#define ICSNEO_NETID_HW_COM_LATENCY_TEST 512
#define ICSNEO_NETID_DEVICE_STATUS 513
#define ICSNEO_NETID_ANY 0xfffe // Never actually set as type, but used as flag for filtering
#define ICSNEO_NETID_INVALID 0xffff
#define ICSNEO_NETWORK_TYPE_INVALID ((uint8_t)0)
#define ICSNEO_NETWORK_TYPE_INTERNAL ((uint8_t)1) // Used for statuses that don't actually need to be transferred to the client application
#define ICSNEO_NETWORK_TYPE_CAN ((uint8_t)2)
#define ICSNEO_NETWORK_TYPE_LIN ((uint8_t)3)
#define ICSNEO_NETWORK_TYPE_FLEXRAY ((uint8_t)4)
#define ICSNEO_NETWORK_TYPE_MOST ((uint8_t)5)
#define ICSNEO_NETWORK_TYPE_ETHERNET ((uint8_t)6)
#define ICSNEO_NETWORK_TYPE_ANY ((uint8_t)0xFE) // Never actually set as type, but used as flag for filtering
#define ICSNEO_NETWORK_TYPE_OTHER ((uint8_t)0xFF)
#define ICSNEO_NETWORK_TYPE_INVALID 0
#define ICSNEO_NETWORK_TYPE_INTERNAL 1 // Used for statuses that don't actually need to be transferred to the client application
#define ICSNEO_NETWORK_TYPE_CAN 2
#define ICSNEO_NETWORK_TYPE_LIN 3
#define ICSNEO_NETWORK_TYPE_FLEXRAY 4
#define ICSNEO_NETWORK_TYPE_MOST 5
#define ICSNEO_NETWORK_TYPE_ETHERNET 6
#define ICSNEO_NETWORK_TYPE_ANY 0xFE // Never actually set as type, but used as flag for filtering
#define ICSNEO_NETWORK_TYPE_OTHER 0xFF
#endif
#endif
@@ -2,6 +2,7 @@
#define __CANPACKET_H__
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/api/eventmanager.h"
#include <cstdint>
#include <memory>
@@ -11,7 +12,7 @@ typedef uint16_t icscm_bitfield;
struct HardwareCANPacket {
static std::shared_ptr<CANMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
struct {
icscm_bitfield IDE : 1;
@@ -2,6 +2,7 @@
#define __ETHERNETPACKET_H__
#include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/api/eventmanager.h"
#include <cstdint>
#include <memory>
@@ -11,7 +12,7 @@ typedef uint16_t icscm_bitfield;
struct HardwareEthernetPacket {
static std::shared_ptr<EthernetMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const EthernetMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& err);
struct {
icscm_bitfield FCS_AVAIL : 1;
@@ -0,0 +1,66 @@
#ifndef __FLEXRAYPACKET_H__
#define __FLEXRAYPACKET_H__
#include "icsneo/communication/message/flexray/flexraymessage.h"
#include "icsneo/api/eventmanager.h"
#include <cstdint>
#include <memory>
namespace icsneo {
struct HardwareFlexRayPacket {
static std::shared_ptr<FlexRayMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const FlexRayMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
//Word 0
uint16_t slotid : 11;
uint16_t startup : 1;
uint16_t sync : 1;
uint16_t null_frame : 1;
uint16_t payload_preamble : 1;
uint16_t reserved_0 : 1;
//Word 1
uint16_t hdr_crc_10 : 1;
uint16_t payload_len : 7;
uint16_t reserved_1 : 4;
uint16_t txmsg : 1;
uint16_t reserved_2 : 3;
//Word 2
uint16_t cycle : 6;
uint16_t hdr_crc_9_0 : 10;
//Word 3 (D0-D1)
union {
uint16_t word;
struct
{
uint16_t bytesRxed : 9;
uint16_t dynamic : 1;
uint16_t chb : 1;
uint16_t hcrc_error : 1;
uint16_t fcrc_error : 1;
uint16_t reserved_3 : 3;
} bits;
} statusBits;
//Word 4 (D2-D3)
uint16_t tss_length_12_5ns;
//Word 5 (D4-D5)
uint16_t frame_length_12_5ns;
//Word 6 (D6-D7)
uint16_t extra;
//Word 7
uint16_t stat;
//Word 8-14 (Timestamp)
struct {
uint64_t TS : 60;
uint64_t : 3; // Reserved for future status bits
uint64_t IsExtended : 1;
} timestamp;
//Word 15 (From Extended Header)
uint16_t NetworkID;
//Word 16 (From Extended Header)
uint16_t Length;
};
}
#endif
+4 -4
View File
@@ -2,7 +2,7 @@
#define __PACKETIZER_H_
#include "icsneo/communication/packet.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include <queue>
#include <vector>
#include <memory>
@@ -13,7 +13,7 @@ class Packetizer {
public:
static uint8_t ICSChecksum(const std::vector<uint8_t>& data);
Packetizer(device_errorhandler_t err) : err(err) {}
Packetizer(device_eventhandler_t report) : report(report) {}
std::vector<uint8_t>& packetWrap(std::vector<uint8_t>& data, bool shortFormat);
@@ -37,12 +37,12 @@ private:
int headerSize = 0;
bool checksum = false;
bool gotGoodPackets = false; // Tracks whether we've ever gotten a good packet
Packet packet;
Packet packet, previousPacket;
std::deque<uint8_t> bytes;
std::vector<std::shared_ptr<Packet>> processedPackets;
device_errorhandler_t err;
device_eventhandler_t report;
};
}
+47 -13
View File
@@ -3,17 +3,21 @@
#include <vector>
#include <memory>
#include <utility>
#include <cstring>
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/device/neodevice.h"
#include "icsneo/device/idevicesettings.h"
#include "icsneo/device/nullsettings.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/communication/communication.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/decoder.h"
#include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/device/extensions/flexray/controller.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/third-party/concurrentqueue/concurrentqueue.h"
namespace icsneo {
@@ -21,7 +25,8 @@ namespace icsneo {
class Device {
public:
virtual ~Device() {
disableMessagePolling();
if(isMessagePollingEnabled())
disableMessagePolling();
close();
}
@@ -44,13 +49,15 @@ public:
virtual bool open();
virtual bool close();
virtual bool isOnline() const { return online; }
virtual bool isOpen() const { return com->isOpen(); }
virtual bool goOnline();
virtual bool goOffline();
// Message polling related functions
void enableMessagePolling();
bool enableMessagePolling();
bool disableMessagePolling();
std::vector<std::shared_ptr<Message>> getMessages();
bool isMessagePollingEnabled() { return messagePollingCallbackID != 0; };
std::pair<std::vector<std::shared_ptr<Message>>, bool> getMessages();
bool getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit = 0, std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
size_t getCurrentMessageCount() { return pollingContainer.size_approx(); }
size_t getPollingMessageLimit() { return pollingMessageLimit; }
@@ -65,6 +72,8 @@ public:
bool transmit(std::shared_ptr<Message> message);
bool transmit(std::vector<std::shared_ptr<Message>> messages);
void setWriteBlocks(bool blocks);
const std::vector<Network>& getSupportedRXNetworks() const { return supportedRXNetworks; }
const std::vector<Network>& getSupportedTXNetworks() const { return supportedTXNetworks; }
virtual bool isSupportedRXNetwork(const Network& net) const {
@@ -77,6 +86,10 @@ public:
virtual size_t getNetworkCountByType(Network::Type) const;
virtual Network getNetworkByNumber(Network::Type, size_t) const;
virtual std::shared_ptr<FlexRay::Controller> getFlexRayControllerByNetwork(const Network&) const { return nullptr; }
const device_eventhandler_t& getEventHandler() const { return report; }
std::shared_ptr<Communication> com;
std::unique_ptr<IDeviceSettings> settings;
@@ -85,7 +98,7 @@ protected:
bool online = false;
int messagePollingCallbackID = 0;
int internalHandlerCallbackID = 0;
device_errorhandler_t err;
device_eventhandler_t report;
// START Initialization Functions
Device(neodevice_t neodevice = { 0 }) {
@@ -95,7 +108,7 @@ protected:
template<typename Transport, typename Settings = NullSettings>
void initialize() {
err = makeErrorHandler();
report = makeEventHandler();
auto transport = makeTransport<Transport>();
setupTransport(*transport);
auto packetizer = makePacketizer();
@@ -110,30 +123,33 @@ protected:
setupSettings(*settings);
setupSupportedRXNetworks(supportedRXNetworks);
setupSupportedTXNetworks(supportedTXNetworks);
setupExtensions();
}
virtual device_errorhandler_t makeErrorHandler() {
return [this](APIError::ErrorType type) { ErrorManager::GetInstance().add(type, this); };
virtual device_eventhandler_t makeEventHandler() {
return [this](APIEvent::Type type, APIEvent::Severity severity) {
EventManager::GetInstance().add(type, severity, this);
};
}
template<typename Transport>
std::unique_ptr<ICommunication> makeTransport() { return std::unique_ptr<ICommunication>(new Transport(err, getWritableNeoDevice())); }
std::unique_ptr<ICommunication> makeTransport() { return std::unique_ptr<ICommunication>(new Transport(report, getWritableNeoDevice())); }
virtual void setupTransport(ICommunication&) {}
virtual std::shared_ptr<Packetizer> makePacketizer() { return std::make_shared<Packetizer>(err); }
virtual std::shared_ptr<Packetizer> makePacketizer() { return std::make_shared<Packetizer>(report); }
virtual void setupPacketizer(Packetizer&) {}
virtual std::unique_ptr<Encoder> makeEncoder(std::shared_ptr<Packetizer> p) { return std::unique_ptr<Encoder>(new Encoder(err, p)); }
virtual std::unique_ptr<Encoder> makeEncoder(std::shared_ptr<Packetizer> p) { return std::unique_ptr<Encoder>(new Encoder(report, p)); }
virtual void setupEncoder(Encoder&) {}
virtual std::unique_ptr<Decoder> makeDecoder() { return std::unique_ptr<Decoder>(new Decoder(err)); }
virtual std::unique_ptr<Decoder> makeDecoder() { return std::unique_ptr<Decoder>(new Decoder(report)); }
virtual void setupDecoder(Decoder&) {}
virtual std::shared_ptr<Communication> makeCommunication(
std::unique_ptr<ICommunication> t,
std::shared_ptr<Packetizer> p,
std::unique_ptr<Encoder> e,
std::unique_ptr<Decoder> d) { return std::make_shared<Communication>(err, std::move(t), p, std::move(e), std::move(d)); }
std::unique_ptr<Decoder> d) { return std::make_shared<Communication>(report, std::move(t), p, std::move(e), std::move(d)); }
virtual void setupCommunication(Communication&) {}
template<typename Settings>
@@ -144,6 +160,20 @@ protected:
virtual void setupSupportedRXNetworks(std::vector<Network>&) {}
virtual void setupSupportedTXNetworks(std::vector<Network>&) {}
virtual void setupExtensions() {}
void addExtension(std::shared_ptr<DeviceExtension>&& extension);
template<typename Extension>
std::shared_ptr<Extension> getExtension() const {
std::shared_ptr<Extension> ret;
std::lock_guard<std::mutex> lk(extensionsLock);
for(auto& ext : extensions) {
if((ret = std::dynamic_pointer_cast<Extension>(ext)))
break;
}
return ret;
}
// END Initialization Functions
void handleInternalMessage(std::shared_ptr<Message> message);
@@ -154,6 +184,10 @@ private:
neodevice_t data;
std::shared_ptr<ResetStatusMessage> latestResetStatus;
mutable std::mutex extensionsLock;
std::vector<std::shared_ptr<DeviceExtension>> extensions;
void forEachExtension(std::function<void(const std::shared_ptr<DeviceExtension>&)> fn);
std::vector<Network> supportedTXNetworks;
std::vector<Network> supportedRXNetworks;
@@ -0,0 +1,26 @@
#ifndef __DEVICEEXTENSION_H_
#define __DEVICEEXTENSION_H_
#include <memory>
#include "icsneo/communication/message/message.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
class Device;
class DeviceExtension {
public:
DeviceExtension(Device& device) : device(device) {}
virtual ~DeviceExtension() = default;
virtual const char* getName() const = 0;
virtual void handleMessage(const std::shared_ptr<Message>&) {}
protected:
Device& device;
};
} // namespace icsneo
#endif // __DEVICEEXTENSION_H_
@@ -0,0 +1,74 @@
#ifndef __FLEXRAYCONTROLLER_H_
#define __FLEXRAYCONTROLLER_H_
#include <cstdint>
#include <memory>
#include <chrono>
#include <mutex>
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/device/extensions/flexray/erayregister.h"
#include "icsneo/device/extensions/flexray/poccommand.h"
namespace icsneo {
class Device;
namespace FlexRay {
class Controller {
public:
Controller(Device& device, uint8_t index) : device(device), index(index) {}
std::shared_ptr<FlexRayControlMessage> getStatus() const;
void _setStatus(std::shared_ptr<FlexRayControlMessage> msg);
bool getAllowColdstart() const { return allowColdstart; }
void setAllowColdstart(bool enable) { allowColdstart = enable; }
bool getWakeupBeforeStart() const { return wakeupBeforeStart; }
void setWakeupBeforeStart(bool enable) { wakeupBeforeStart = enable; }
void getReady();
void start();
private:
bool isPOCBusy() const { return readRegisterOr(ERAYRegister::SUCC1, 0x00000080) & 0x00000080; }
std::pair<bool, FlexRay::POCCommand> getCurrentPOCCommand(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) const;
bool setCurrentPOCCommand(
FlexRay::POCCommand cmd,
bool checkForSuccess = true,
std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
bool wasCommandSuccessful(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) const;
std::pair<bool, uint32_t> readRegister(
ERAYRegister reg,
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) const;
uint32_t readRegisterOr(
ERAYRegister reg,
uint32_t defaultValue = 0,
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) const;
bool writeRegister(
ERAYRegister reg,
uint32_t value,
uint32_t mask,
bool waitForPOCReady = true,
std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
bool writeRegister(
ERAYRegister reg,
uint32_t value,
bool waitForPOCReady = true,
std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
Device& device;
uint8_t index;
mutable std::mutex statusLock;
mutable std::mutex readRegisterLock;
std::shared_ptr<FlexRayControlMessage> status;
bool allowColdstart = false;
bool wakeupBeforeStart = false;
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYCONTROLLER_H_
@@ -0,0 +1,20 @@
#ifndef __FLEXRAYCRCSTATUS_H_
#define __FLEXRAYCRCSTATUS_H_
#include <cstdint>
namespace icsneo {
namespace FlexRay {
enum class CRCStatus {
OK = 0,
Error,
NoCRC
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYCRCSTATUS_H_
@@ -0,0 +1,116 @@
#ifndef __ERAYREGISTER_H_
#define __ERAYREGISTER_H_
#include <cstdint>
namespace icsneo {
enum class ERAYRegister : uint32_t {
// Customer Registers : Not Part of ERAY, part of FUJITSU FlexRay ASSP MB88121C
VER = 0x0000,// Version Information Register reset = 0440_79FF Access = r
CCNT = 0x0004,// Clock Control Register reset = 0000_0000 Access = r/w
DBGS_DMAS = 0x0008,// Debug Support Register / DMA Support Register reset = 0000_0000 Acess = r/w
INT_REG = 0x000C,// Interrupt Register Register reset = 0000_0000 Acess = r/w
LCK = 0x001C,// Lock Register reset = 0000_0000 Acess = r/w
// Interrupt-Related Registers
EIR = 0x0020,// Error Interrupt Register reset=0000_0000 Access = r/w
SIR = 0x0024,// Status Interrupt Register 0000_0000 r/w
EILS = 0x0028,// Error Interrupt Line Select Register 0000_0000 r/w
SILS = 0x002C,// Status Interrupt Line Select Register 0303_FFFF r/w
EIES = 0x0030,// Error Interrupt Enable Register (set) 0000_0000 r/w
EIER = 0x0034,// Error Interrupt Enable Register (reset) 0000_0000 r/w
SIES = 0x0038,// Status Interrupt Enable Register (set) 0000_0000 r/w
SIER = 0x003C,// Status Interrupt Enable Register (reset) 0000_0000 r/w
ILE = 0x0040,// Interrupt Line Enable Register 0000_0000 r/w
T0C = 0x0044,// Timer 0 Configuration Register 0 0000_0000 r/w
T1C = 0x0048,// Timer 0 Configuration Register 1 0002_0000 r/w
STPW1 = 0x004C,// Stop Watch Register 1 0000_0000 r/w
STPW2 = 0x0050,// Stop Watch Register 2 0000_0000 r
//0x00540x007C- reserved(11) 0000_0000 r
// System Universal Control (SUC)
// The system universal control controls the following functions.
// Configuration
// Wakeup
// Startup
// Normal operation
// Passive operation
// Monitor mode
SUCC1 = 0x0080,// SUC Configuration Register 1 0C40_1000 r/w
SUCC2 = 0x0084,// SUC Configuration Register 2 0100_0504 r/w
SUCC3 = 0x0088,// SUC Configuration Register 3 0000_0011 r/w
// Network Management (NEM)
// Sets the handling of the network management vector
NEMC = 0x008C,// NEM Configuration Register 0000_0000 r/w
PRTC1 = 0x0090,// PRT Configuration Register 1 084C_0633 r/w
PRTC2 = 0x0094,// PRT Configuration Register 2 0F2D_0A0E r/w
MHDC = 0x0098,// MHD Configuration Register 0000_0000 r/w
GTUC1 = 0x00A0,// GTU Configuration Register 1 0000_0280 r/w
GTUC2 = 0x00A4,// GTU Configuration Register 2 0002_000A r/w
GTUC3 = 0x00A8,// GTU Configuration Register 3 0202_0000 r/w
GTUC4 = 0x00AC,// GTU Configuration Register 4 0008_0007 r/w
GTUC5 = 0x00B0,// GTU Configuration Register 5 0E00_0000 r/w
GTUC6 = 0x00B4,// GTU Configuration Register 6 0002_0000 r/w
GTUC7 = 0x00B8,// GTU Configuration Register 7 0002_0004 r/w
GTUC8 = 0x00BC,// GTU Configuration Register 8 0000_0002 r/w
GTUC9 = 0x00C0,// GTU Configuration Register 9 0000_0101 r/w
GTUC10 = 0x00C4,// GTU Configuration Register 10 0002_0005 r/w
GTUC11 = 0x00C8,// GTU Configuration Register 11 0000_0000 r/w
CCSV = 0x0100,// CC Status Vector Register 0010_4000 r
CCEV = 0x0104,// CC Error Vector Register 0000_0000 r
// 0x0108 =-0x010C, reserved(2) 0000_0000 r
SCV = 0x0110,//Slot Counter Value Register 0000_0000 r
MTCCV = 0x0114,//Macrotick and Cycle Counter Value Register 0000_0000 r
RCV = 0x0118,//Rate Correction Value Register 0000_0000 r
OCV = 0x011C,//Offset Correction Value Register 0000_0000 r
SFS = 0x0120,//Sync Frame Status Register 0000_0000 r
SWNIT = 0x0124,//Symbol Window and NIT Status Register 0000_0000 r
ACS = 0x0128,//Aggregated Channel Status Register 0000_0000 r/w -
ESID_START = 0x0130,
ESID_END = 0x0168,
OSID_START = 0x0170,
OSID_END = 0x01A8,
NMV1 = 0x01B0,
NMV2 = 0x01B4,
NMV3 = 0x01B8,
// Message Buffer Control Registers
MRC = 0x0300,// Message RAM Configuration Register 0180_0000 r/w
FRF = 0x0304,// FIFO Rejection Filter Register 0180_0000 r/w
FRFM = 0x0308,// FIFO Rejection Filter Mask Register 0000_0000 r/w
FCL = 0x030C,// FIFO Critical Level Register 0000_0080 r/w
// Message Buffer Status Registers
MHDS = 0x0310,// Message Handler Status Register 0000_0000 r/w
LDTS = 0x0314,// Last Dynamic Transmit Slot Register 0000_0000 r
FSR = 0x0318,// FIFO Status Register 0000_0000 r
MHDF = 0x031C,// Message Handler Constraints Flags Register 0000_0000 r/w
TXRQ1 = 0x0320,// Transmission Request Register 1 0000_0000 r
TXRQ2 = 0x0324,// Transmission Request Register 2 0000_0000 r
TXRQ3 = 0x0328,// Transmission Request Register 3 0000_0000 r
TXRQ4 = 0x032C,// Transmission Request Register 4 0000_0000 r
NDAT1 = 0x0330,// New Data Register 1 0000_0000 r
NDAT2 = 0x0334,// New Data Register 2 0000_0000 r
WRHS1 = 0x0500,// Write Header Section Register 1
WRHS2 = 0x0504,// Write Header Section Register 2
WRHS3 = 0x0508,// Write Header Section Register 3
IBCM = 0x0510,// Input Buffer Command Mask Register
IBCR = 0x0514,// Input Buffer Command Request Register
OBCM = 0x710,
OBCR = 0x714,
};
} // namespace icsneo
#endif // __ERAYREGISTER_H_
@@ -0,0 +1,38 @@
#ifndef __FLEXRAYEXTENSION_H_
#define __FLEXRAYEXTENSION_H_
#include <mutex>
#include <memory>
#include <utility>
#include "icsneo/device/extensions/flexray/erayregister.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/device/extensions/deviceextension.h"
namespace icsneo {
namespace FlexRay {
class Controller;
class Extension : public DeviceExtension {
public:
Extension(Device& device, uint8_t controllerCount);
const char* getName() const override { return "FlexRay"; }
void handleMessage(const std::shared_ptr<Message>& message) override;
std::shared_ptr<Controller> getController(uint8_t index) const {
if(index >= controllers.size())
return nullptr;
return controllers[index];
}
private:
std::vector<std::shared_ptr<Controller>> controllers;
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYEXTENSION_H_
@@ -0,0 +1,26 @@
#ifndef __FLEXRAYOPCODE_H_
#define __FLEXRAYOPCODE_H_
#include <cstdint>
namespace icsneo {
namespace FlexRay {
// Second byte, opcode
enum class Opcode : uint8_t {
SetNetID = 0x00,
ReadCCRegs = 0x01,
WriteCCReg = 0x02,
WriteMessageBuffer = 0x03,
ReadCCStatus = 0x04,
AddConfiguredMessage = 0x05,
InitForRun = 0x06,
Unknown = 0xff
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYOPCODE_H_
@@ -0,0 +1,31 @@
#ifndef __FLEXRAYPOCCOMMAND_H_
#define __FLEXRAYPOCCOMMAND_H_
#include <cstdint>
namespace icsneo {
namespace FlexRay {
enum class POCCommand : uint8_t {
CommandNotAccepted = 0x00,
Config = 0x01,
Ready = 0x02,
Wakeup = 0x03,
Run = 0x04,
AllSlots = 0x05,
Halt = 0x06,
Freeze = 0x07,
SendMTS = 0x08,
AllowColdstart = 0x09,
ResetStatusIndicators = 0x0a,
MonitorMode = 0x0b,
ClearRAMs = 0x0c,
Unknown = 0xff
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYPOCCOMMAND_H_
@@ -0,0 +1,40 @@
#ifndef __FLEXRAYPOCSTATUS_H_
#define __FLEXRAYPOCSTATUS_H_
#include <cstdint>
namespace icsneo {
namespace FlexRay {
enum class POCStatus : uint8_t {
DefaultConfig = 0x00,
Ready = 0x01,
NormalActive = 0x02,
NormalPassive = 0x03,
Halt = 0x04,
MonitorMode = 0x05,
WakeupStandby = 0x10,
WakeupListen = 0x11,
WakeupSend = 0x12,
WakeupDetect = 0x13,
StartupPrepare = 0x20,
ColdstartListen = 0x21,
ColdstartCollisionResolution = 0x22,
ColdstartConsistencyCheck = 0x23,
ColdstartGap = 0x24,
ColdstartJoin = 0x25,
IntegrationColdstartCheck = 0x26,
IntegrationListen = 0x27,
IntegrationConsistencyCheck = 0x28,
InitializeSchedule = 0x29,
AbortStartup = 0x2a,
StartupSuccess = 0x2b,
Unknown = 0xff
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYPOCSTATUS_H_
@@ -0,0 +1,21 @@
#ifndef __FLEXRAYSYMBOL_H_
#define __FLEXRAYSYMBOL_H_
#include <cstdint>
namespace icsneo {
namespace FlexRay {
enum class Symbol {
None = 0,
Unknown,
Wakeup,
CAS
};
} // namespace FlexRay
} // namespace icsneo
#endif // __FLEXRAYSYMBOL_H_
+7 -3
View File
@@ -334,7 +334,7 @@ public:
static CANBaudrate GetEnumValueForBaudrate(int64_t baudrate);
static int64_t GetBaudrateValueForEnum(CANBaudrate enumValue);
IDeviceSettings(std::shared_ptr<Communication> com, size_t size) : com(com), err(com->err), structSize(size) {}
IDeviceSettings(std::shared_ptr<Communication> com, size_t size) : com(com), report(com->report), structSize(size) {}
virtual ~IDeviceSettings() {}
bool ok() { return !disabled && settingsLoaded; }
@@ -399,13 +399,17 @@ public:
const size_t& getSize() const { return structSize; }
// if settings are disabled for this device. always false unless constructed null
bool disabled = false;
bool readonly = false;
bool disableGSChecksumming = false;
protected:
std::shared_ptr<Communication> com;
device_errorhandler_t err;
device_eventhandler_t report;
size_t structSize;
// if we hold any local copies of the device settings
bool settingsLoaded = false;
std::vector<uint8_t> settings; // For writing settings to, calling apply() should copy over to device RAM (and EEPROM)
@@ -414,7 +418,7 @@ protected:
// Parameter createInoperableSettings exists because it is serving as a warning that you probably don't want to do this
typedef void* warn_t;
IDeviceSettings(warn_t createInoperableSettings, std::shared_ptr<Communication> com)
: disabled(true), readonly(true), err(com->err), structSize(0) { (void)createInoperableSettings; }
: disabled(true), readonly(true), report(com->report), structSize(0) { (void)createInoperableSettings; }
};
}
-29
View File
@@ -1,29 +0,0 @@
#ifndef __PLASION_H_
#define __PLASION_H_
#include "icsneo/device/device.h"
#include "icsneo/communication/multichannelcommunication.h"
#include "icsneo/platform/ftdi.h"
namespace icsneo {
class Plasion : public Device {
protected:
virtual std::shared_ptr<Communication> makeCommunication(
std::unique_ptr<ICommunication> transport,
std::shared_ptr<Packetizer> packetizer,
std::unique_ptr<Encoder> encoder,
std::unique_ptr<Decoder> decoder
) override { return std::make_shared<MultiChannelCommunication>(err, std::move(transport), packetizer, std::move(encoder), std::move(decoder)); }
// TODO: This is done so that Plasion can still transmit it's basic networks, awaiting VLAN support
virtual bool isSupportedRXNetwork(const Network&) const override { return true; }
virtual bool isSupportedTXNetwork(const Network&) const override { return true; }
public:
Plasion(neodevice_t neodevice) : Device(neodevice) {}
};
}
#endif
@@ -4,7 +4,7 @@
#include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/neovifire/neovifiresettings.h"
#include "icsneo/device/tree/neovifire/neovifiresettings.h"
namespace icsneo {
@@ -1,9 +1,9 @@
#ifndef __NEOVIFIRE2ETH_H_
#define __NEOVIFIRE2ETH_H_
#include "icsneo/device/neovifire2/neovifire2.h"
#include "icsneo/device/tree/neovifire2/neovifire2.h"
#include "icsneo/platform/pcap.h"
#include "icsneo/device/neovifire2/neovifire2settings.h"
#include "icsneo/device/tree/neovifire2/neovifire2settings.h"
#include <memory>
namespace icsneo {
@@ -1,9 +1,9 @@
#ifndef __NEOVIFIRE2USB_H_
#define __NEOVIFIRE2USB_H_
#include "icsneo/device/neovifire2/neovifire2.h"
#include "icsneo/device/tree/neovifire2/neovifire2.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/neovifire2/neovifire2settings.h"
#include "icsneo/device/tree/neovifire2/neovifire2settings.h"
namespace icsneo {
@@ -1,7 +1,7 @@
#ifndef __NEOVIION_H_
#define __NEOVIION_H_
#include "icsneo/device/plasion/plasion.h"
#include "icsneo/device/tree/plasion/plasion.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
@@ -1,7 +1,7 @@
#ifndef __NEOVIPLASMA_H_
#define __NEOVIPLASMA_H_
#include "icsneo/device/plasion/plasion.h"
#include "icsneo/device/tree/plasion/plasion.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
@@ -0,0 +1,91 @@
#ifndef __PLASION_H_
#define __PLASION_H_
#include "icsneo/device/device.h"
#include "icsneo/communication/multichannelcommunication.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/extensions/flexray/extension.h"
namespace icsneo {
class Plasion : public Device {
protected:
virtual std::shared_ptr<Communication> makeCommunication(
std::unique_ptr<ICommunication> transport,
std::shared_ptr<Packetizer> packetizer,
std::unique_ptr<Encoder> encoder,
std::unique_ptr<Decoder> decoder
) override { return std::make_shared<MultiChannelCommunication>(report, std::move(transport), packetizer, std::move(encoder), std::move(decoder)); }
// TODO: This is done so that Plasion can still transmit it's basic networks, awaiting VLAN support
virtual bool isSupportedRXNetwork(const Network&) const override { return true; }
virtual bool isSupportedTXNetwork(const Network&) const override { return true; }
virtual void setupExtensions() override {
addExtension(std::make_shared<FlexRay::Extension>(*this, (uint8_t)2));
}
static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = {
Network::NetID::HSCAN,
Network::NetID::MSCAN,
Network::NetID::HSCAN2,
Network::NetID::HSCAN3,
Network::NetID::HSCAN4,
Network::NetID::HSCAN5,
Network::NetID::HSCAN6,
Network::NetID::HSCAN7,
Network::NetID::LSFTCAN,
Network::NetID::LSFTCAN2,
Network::NetID::SWCAN,
Network::NetID::SWCAN2,
Network::NetID::Ethernet,
Network::NetID::LIN,
Network::NetID::LIN2,
Network::NetID::LIN3,
Network::NetID::LIN4,
Network::NetID::FlexRay,
Network::NetID::FlexRay2
};
return supportedNetworks;
}
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid);
}
virtual std::shared_ptr<FlexRay::Controller> getFlexRayControllerByNetwork(const Network& net) const override {
uint8_t idx = 0xff;
switch(net.getNetID()) {
case Network::NetID::FlexRay:
idx = 0;
break;
case Network::NetID::FlexRay2:
idx = 1;
break;
default:
return Device::getFlexRayControllerByNetwork(net);
}
auto extension = getExtension<FlexRay::Extension>();
if(!extension)
return Device::getFlexRayControllerByNetwork(net);
auto res = extension->getController(idx);
if(!res)
return Device::getFlexRayControllerByNetwork(net);
return res;
}
public:
Plasion(neodevice_t neodevice) : Device(neodevice) {}
};
}
#endif
@@ -44,11 +44,6 @@ protected:
encoder.supportCANFD = true;
}
virtual void setupDecoder(Decoder& decoder) override {
Device::setupDecoder(decoder);
decoder.timestampResolution = 10; // Timestamps are in 10ns increments instead of the usual 25ns
}
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid);
@@ -1,7 +1,7 @@
#ifndef __RADPLUTOUSB_H_
#define __RADPLUTOUSB_H_
#include "icsneo/device/radpluto/radpluto.h"
#include "icsneo/device/tree/radpluto/radpluto.h"
#include "icsneo/platform/stm32.h"
namespace icsneo {
@@ -3,7 +3,7 @@
#include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/device/radstar2/radstar2settings.h"
#include "icsneo/device/tree/radstar2/radstar2settings.h"
namespace icsneo {
@@ -1,7 +1,7 @@
#ifndef __RADSTAR2ETH_H_
#define __RADSTAR2ETH_H_
#include "icsneo/device/radstar2/radstar2.h"
#include "icsneo/device/tree/radstar2/radstar2.h"
#include "icsneo/communication/network.h"
#include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/platform/pcap.h"
@@ -1,7 +1,7 @@
#ifndef __RADSTAR2USB_H_
#define __RADSTAR2USB_H_
#include "icsneo/device/radstar2/radstar2.h"
#include "icsneo/device/tree/radstar2/radstar2.h"
#include "icsneo/platform/ftdi.h"
namespace icsneo {
@@ -4,7 +4,7 @@
#include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/valuecan3/valuecan3settings.h"
#include "icsneo/device/tree/valuecan3/valuecan3settings.h"
namespace icsneo {
@@ -2,7 +2,7 @@
#define __VALUECAN4_1_2_SETTINGS_H_
#include "icsneo/device/idevicesettings.h"
#include "icsneo/device/valuecan4/settings/valuecan4settings.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4settings.h"
#ifdef __cplusplus
@@ -1,7 +1,7 @@
#ifndef __VALUECAN4_1_SETTINGS_H_
#define __VALUECAN4_1_SETTINGS_H_
#include "icsneo/device/valuecan4/settings/valuecan4-1-2settings.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-1-2settings.h"
#ifdef __cplusplus
@@ -2,7 +2,7 @@
#define __VALUECAN4_2EL_SETTINGS_H_
#include "icsneo/device/idevicesettings.h"
#include "icsneo/device/valuecan4/settings/valuecan4-4-2elsettings.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-4-2elsettings.h"
#ifdef __cplusplus
@@ -1,7 +1,7 @@
#ifndef __VALUECAN4_2_SETTINGS_H_
#define __VALUECAN4_2_SETTINGS_H_
#include "icsneo/device/valuecan4/settings/valuecan4-1-2settings.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-1-2settings.h"
#ifdef __cplusplus
@@ -2,7 +2,7 @@
#define __VALUECAN4_4_2EL_SETTINGS_H_
#include "icsneo/device/idevicesettings.h"
#include "icsneo/device/valuecan4/settings/valuecan4settings.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4settings.h"
#ifdef __cplusplus
@@ -2,7 +2,7 @@
#define __VALUECAN4_4_SETTINGS_H_
#include "icsneo/device/idevicesettings.h"
#include "icsneo/device/valuecan4/settings/valuecan4-4-2elsettings.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-4-2elsettings.h"
#ifdef __cplusplus
@@ -1,8 +1,8 @@
#ifndef __VALUECAN4_1_H_
#define __VALUECAN4_1_H_
#include "icsneo/device/valuecan4/valuecan4.h"
#include "icsneo/device/valuecan4/settings/valuecan4-1settings.h"
#include "icsneo/device/tree/valuecan4/valuecan4.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-1settings.h"
#include <string>
namespace icsneo {
@@ -1,8 +1,8 @@
#ifndef __VALUECAN4_2_H_
#define __VALUECAN4_2_H_
#include "icsneo/device/valuecan4/valuecan4.h"
#include "icsneo/device/valuecan4/settings/valuecan4-2settings.h"
#include "icsneo/device/tree/valuecan4/valuecan4.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-2settings.h"
#include <string>
namespace icsneo {
@@ -1,8 +1,8 @@
#ifndef __VALUECAN4_2EL_H_
#define __VALUECAN4_2EL_H_
#include "icsneo/device/valuecan4/valuecan4.h"
#include "icsneo/device/valuecan4/settings/valuecan4-2elsettings.h"
#include "icsneo/device/tree/valuecan4/valuecan4.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-2elsettings.h"
#include <string>
namespace icsneo {
@@ -1,8 +1,8 @@
#ifndef __VALUECAN4_4_H_
#define __VALUECAN4_4_H_
#include "icsneo/device/valuecan4/valuecan4.h"
#include "icsneo/device/valuecan4/settings/valuecan4-4settings.h"
#include "icsneo/device/tree/valuecan4/valuecan4.h"
#include "icsneo/device/tree/valuecan4/settings/valuecan4-4settings.h"
#include <string>
namespace icsneo {
+192 -86
View File
@@ -2,12 +2,14 @@
#define __ICSNEOC_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "icsneo/device/neodevice.h" // For neodevice_t
#include "icsneo/communication/message/neomessage.h" // For neomessage_t and friends
#include "icsneo/platform/dynamiclib.h" // Dynamic library loading and exporting
#include "icsneo/communication/network.h" // Network type and netID defines
#include "icsneo/api/version.h" // For version info
#include "icsneo/api/error.h" // For error info
#include "icsneo/api/event.h" // For event and error info
#ifndef ICSNEOC_DYNAMICLOAD
@@ -31,7 +33,7 @@ extern "C" {
* To invoke this behavior without finding devices again, call icsneo_freeUnconnectedDevices().
*
* If the size provided is not large enough, the output will be truncated.
* An icsneo::APIError::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* An icsneo::APIEvent::OutputTruncatedError will be available in icsneo_getLastError() in this case.
*/
extern void DLLExport icsneo_findAllDevices(neodevice_t* devices, size_t* count);
@@ -43,7 +45,7 @@ extern void DLLExport icsneo_findAllDevices(neodevice_t* devices, size_t* count)
extern void DLLExport icsneo_freeUnconnectedDevices();
/**
* \brief Convert a serial number in numerical format to it's string representation.
* \brief Convert a serial number in numerical format to its string representation.
* \param[in] num A numerical serial number.
* \param[out] str A pointer to a buffer where the string representation will be written. NULL can be passed, which will write a character count to `count`.
* \param[inout] count A pointer to a size_t which, prior to the call,
@@ -62,13 +64,13 @@ extern void DLLExport icsneo_freeUnconnectedDevices();
*
* If the size provided is not large enough, the output will be **NOT** be truncated.
* Nothing will be written to the output.
* Instead, an icsneo::APIError::BufferInsufficient will be available in icsneo_getLastError().
* Instead, an icsneo::APIEvent::BufferInsufficient will be available in icsneo_getLastError().
* False will be returned, and `count` will now contain the number of *bytes* necessary to store the full string.
*/
extern bool DLLExport icsneo_serialNumToString(uint32_t num, char* str, size_t* count);
/**
* \brief Convert a serial number in string format to it's numerical representation.
* \brief Convert a serial number in string format to its numerical representation.
* \param[in] str A NULL terminated string containing the string representation of an Intrepid serial number.
* \returns The numerical representation of the serial number, or 0 if the conversion was unsuccessful.
*
@@ -84,7 +86,7 @@ extern uint32_t DLLExport icsneo_serialStringToNum(const char* str);
* \returns True if the neodevice_t is valid.
*
* This check is automatically performed at the beginning of any API function that operates on a device.
* If there is a failure, an icsneo::APIError::InvalidNeoDevice will be available in icsneo_getLastError().
* If there is a failure, an icsneo::APIEvent::InvalidNeoDevice will be available in icsneo_getLastError().
*
* See icsneo_findAllDevices() for information regarding the neodevice_t validity contract.
*/
@@ -100,7 +102,9 @@ extern bool DLLExport icsneo_isValidNeoDevice(const neodevice_t* device);
* See icsneo_goOnline() for information about enabling network communication once the device is open.
*
* If the open did not succeed, icsneo_getLastError() should provide more information about why.
*/ // TODO Solidify what happens in case the connection was already open
*
* If the device was already open, an icsneo::APIEvent::DeviceCurrentlyOpen will be available in icsneo_getLastError().
*/
extern bool DLLExport icsneo_openDevice(const neodevice_t* device);
/**
@@ -113,6 +117,17 @@ extern bool DLLExport icsneo_openDevice(const neodevice_t* device);
*/
extern bool DLLExport icsneo_closeDevice(const neodevice_t* device);
/**
* \brief Verify network connection for the specified hardware
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \returns True if the device is connected.
*
* This function does not modify the working state of the device at all.
*
* See icsneo_openDevice() for an explanation about the concept of being "open".
*/
extern bool DLLExport icsneo_isOpen(const neodevice_t* device);
/**
* \brief Enable network communication for the specified hardware
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
@@ -133,7 +148,7 @@ extern bool DLLExport icsneo_goOnline(const neodevice_t* device);
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \returns True if communication could be disabled.
*
* See icsneo_goOnline() for an explaination about the concept of being "online".
* See icsneo_goOnline() for an explanation about the concept of being "online".
*/
extern bool DLLExport icsneo_goOffline(const neodevice_t* device);
@@ -144,7 +159,7 @@ extern bool DLLExport icsneo_goOffline(const neodevice_t* device);
*
* This function does not modify the working state of the device at all.
*
* See icsneo_goOnline() for an explaination about the concept of being "online".
* See icsneo_goOnline() for an explanation about the concept of being "online".
*/
extern bool DLLExport icsneo_isOnline(const neodevice_t* device);
@@ -167,7 +182,9 @@ extern bool DLLExport icsneo_isOnline(const neodevice_t* device);
* The client application will have to call icsneo_getMessages() very often to avoid losing messages, or change the limit.
*
* If the message limit is exceeded before a call to icsneo_getMessages() takes ownership of the messages,
* the oldest message will be dropped (**LOST**) and an icsneo::APIError::PollingMessageOverflow will be flagged for the device.
* the oldest message will be dropped (**LOST**) and an icsneo::APIEvent::PollingMessageOverflow will be flagged for the device.
*
* This function will succeed even if the device is not open.
*/
extern bool DLLExport icsneo_enableMessagePolling(const neodevice_t* device);
@@ -182,6 +199,17 @@ extern bool DLLExport icsneo_enableMessagePolling(const neodevice_t* device);
*/
extern bool DLLExport icsneo_disableMessagePolling(const neodevice_t* device);
/**
* \brief Verify message polling status for the specified hardware
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \returns True if polling is enabled.
*
* This function does not modify the working state of the device at all.
*
* See icsneo_enableMessagePolling() for an explanation about how polling works.
*/
extern bool DLLExport icsneo_isMessagePollingEnabled(const neodevice_t* device);
/**
* \brief Read out messages which have been recieved
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
@@ -237,11 +265,11 @@ extern bool DLLExport icsneo_getMessages(const neodevice_t* device, neomessage_t
/**
* \brief Get the maximum number of messages which will be held in the API managed buffer for the specified hardware.
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \returns Number of messages.
* \returns Number of messages, or -1 if device is invalid.
*
* See icsneo_enableMessagePolling() for more information about the message polling system.
*/
extern size_t DLLExport icsneo_getPollingMessageLimit(const neodevice_t* device);
extern int DLLExport icsneo_getPollingMessageLimit(const neodevice_t* device);
/**
* \brief Set the maximum number of messages which will be held in the API managed buffer for the specified hardware.
@@ -252,10 +280,27 @@ extern size_t DLLExport icsneo_getPollingMessageLimit(const neodevice_t* device)
* See icsneo_enableMessagePolling() for more information about the message polling system.
*
* Setting the maximum lower than the current number of stored messages will cause the oldest messages
* to be dropped (**LOST**) and an icsneo::APIError::PollingMessageOverflow to be flagged for the device.
* to be dropped (**LOST**) and an icsneo::APIEvent::PollingMessageOverflow to be flagged for the device.
*/
extern bool DLLExport icsneo_setPollingMessageLimit(const neodevice_t* device, size_t newLimit);
/**
* \brief Adds a message callback to the specified device to be called when a new message is received.
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \param[in] callback A function pointer with void return type and a single neomessage_t parameter.
* \param[in] filter Unused for now. Exists as a placeholder here for future backwards-compatibility.
* \returns The id of the callback added, or -1 if the operation failed.
*/
extern int DLLExport icsneo_addMessageCallback(const neodevice_t* device, void (*callback)(neomessage_t), void*);
/**
* \brief Removes a message callback from the specified device.
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \param[in] id The id of the callback to remove.
* \returns True if the callback was successfully removed.
*/
extern bool DLLExport icsneo_removeMessageCallback(const neodevice_t* device, int id);
/**
* \brief Get the friendly product name for a specified device.
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
@@ -275,7 +320,7 @@ extern bool DLLExport icsneo_setPollingMessageLimit(const neodevice_t* device, s
* icsneo_getLastError() should be checked to verify that the neodevice_t provided was valid.
*
* If the size provided is not large enough, the output will be truncated.
* An icsneo::APIError::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* An icsneo::APIEvent::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* True will still be returned.
*/
extern bool DLLExport icsneo_getProductName(const neodevice_t* device, char* str, size_t* maxLength);
@@ -299,7 +344,7 @@ extern bool DLLExport icsneo_getProductName(const neodevice_t* device, char* str
* icsneo_getLastError() should be checked to verify that the neodevice_t provided was valid.
*
* If the size provided is not large enough, the output will be truncated.
* An icsneo::APIError::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* An icsneo::APIEvent::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* True will still be returned.
*/
extern bool DLLExport icsneo_getProductNameForType(devicetype_t type, char* str, size_t* maxLength);
@@ -362,7 +407,7 @@ extern bool DLLExport icsneo_settingsApplyDefaultsTemporary(const neodevice_t* d
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
* \param[out] structure A pointer to a device settings structure for the current device.
* \param[in] structureSize The size of the current device settings structure in bytes.
* \returns Number of bytes written to structure
* \returns Number of bytes written to structure, or -1 if the operation failed.
*
* See icsneo_settingsApply() for further information about applying settings. See icsneo_settingsApplyDefaults() for further information about applying default settings.
*
@@ -371,7 +416,7 @@ extern bool DLLExport icsneo_settingsApplyDefaultsTemporary(const neodevice_t* d
* If possible, use functions specific to the operation you want to acomplish (such as icsneo_setBaudrate()) instead of modifying the structure directly.
* This allows the client application to work with other hardware.
*/
extern size_t DLLExport icsneo_settingsReadStructure(const neodevice_t* device, void* structure, size_t structureSize);
extern int DLLExport icsneo_settingsReadStructure(const neodevice_t* device, void* structure, size_t structureSize);
/**
* \brief Apply a provided settings structure for a specified device.
@@ -504,6 +549,15 @@ extern bool DLLExport icsneo_transmit(const neodevice_t* device, const neomessag
*/
extern bool DLLExport icsneo_transmitMessages(const neodevice_t* device, const neomessage_t* messages, size_t count);
/**
* \brief Set the behavior of whether writing is a blocking action or not.
* \param[in] device A pointer to the neodevice_t structure specifying the device to transmit on.
* \param[in] blocks Whether or not writing is a blocking action.
*
* By default, writing is a blocking action.
*/
extern void DLLExport icsneo_setWriteBlocks(const neodevice_t* device, bool blocks);
/**
* \brief Get the friendly description for a specified device.
* \param[in] device A pointer to the neodevice_t structure specifying the device to operate on.
@@ -523,7 +577,7 @@ extern bool DLLExport icsneo_transmitMessages(const neodevice_t* device, const n
* icsneo_getLastError() should be checked to verify that the neodevice_t provided was valid.
*
* If the size provided is not large enough, the output will be truncated.
* An icsneo::APIError::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* An icsneo::APIEvent::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* True will still be returned.
*/
extern bool DLLExport icsneo_describeDevice(const neodevice_t* device, char* str, size_t* maxLength);
@@ -535,77 +589,101 @@ extern bool DLLExport icsneo_describeDevice(const neodevice_t* device, char* str
extern neoversion_t DLLExport icsneo_getVersion(void);
/**
* \brief Read out errors which have occurred in API operation
* \param[out] errors A pointer to a buffer which neoerror_t structures will be written to. NULL can be passed, which will write the current error count to size.
* \brief Adds an event callback to be called when a new event is added.
* \param[in] callback A function pointer with void return type and a single neoevent_t parameter.
* \param[in] filter Unused for now. Exists as a placeholder here for future backwards-compatibility.
* \returns The id of the callback added. Does not error.
*
* Do not attempt to add or remove callbacks inside of a callback, as the stored callbacks are locked during calls.
*/
extern int DLLExport icsneo_addEventCallback(void (*callback)(neoevent_t), void*);
/**
* \brief Removes an event callback.
* \param[in] id The id of the callback to remove.
* \returns True if the callback was successfully removed.
*/
extern bool DLLExport icsneo_removeEventCallback(int id);
/**
* \brief Read out events which have occurred in API operation
* \param[out] events A pointer to a buffer which neoevent_t structures will be written to. NULL can be passed, which will write the current event count to size.
* \param[inout] size A pointer to a size_t which, prior to the call,
* holds the maximum number of errors to be written, and after the call holds the number of errors written.
* \returns True if the errors were read out successfully (even if there were no errors to report).
* holds the maximum number of events to be written, and after the call holds the number of events written.
* \returns True if the events were read out successfully (even if there were no events to report).
*
* Errors can be caused by API usage, such as bad input or operating on a closed neodevice_t.
* Events contain INFO and WARNINGS, and may potentially contain one TooManyEvents WARNING at the end. No ERRORS are found in Events, see icsneo_getLastError() instead.
*
* Errors can also occur asynchronously to the client application threads, in the case of a device communication error or similar.
* Events can be caused by API usage, such as providing too small of a buffer or disconnecting from a device.
*
* Errors are read out of the API managed buffer in order of oldest to newest.
* Events can also occur asynchronously to the client application threads, in the case of a device communication event or similar.
*
* Events are read out of the API managed buffer in order of oldest to newest.
* As they are read out, they are removed from the API managed buffer.
*
* If size is too small to contain all errors, as many errors as will fit will be read out.
* Subsequent calls to icsneo_getErrors() can retrieve any errors which were not read out.
* If size is too small to contain all events, as many events as will fit will be read out.
* Subsequent calls to icsneo_getEvents() can retrieve any events which were not read out.
*/
extern bool DLLExport icsneo_getErrors(neoerror_t* errors, size_t* size);
extern bool DLLExport icsneo_getEvents(neoevent_t* events, size_t* size);
/**
* \brief Read out errors which have occurred in API operation for a specific device
* \param[in] device A pointer to the neodevice_t structure specifying the device to read out errors for. NULL can be passed, which indicates that **ONLY** errors *not* associated with a device are desired (API errors).
* \param[out] errors A pointer to a buffer which neoerror_t structures will be written to. NULL can be passed, which will write the current error count to size.
* \brief Read out events which have occurred in API operation for a specific device
* \param[in] device A pointer to the neodevice_t structure specifying the device to read out events for. NULL can be passed, which indicates that **ONLY** events *not* associated with a device are desired (API events).
* \param[out] events A pointer to a buffer which neoevent_t structures will be written to. NULL can be passed, which will write the current event count to size.
* \param[inout] size A pointer to a size_t which, prior to the call,
* holds the maximum number of errors to be written, and after the call holds the number of errors written.
* \returns True if the errors were read out successfully (even if there were no errors to report).
* holds the maximum number of events to be written, and after the call holds the number of events written.
* \returns True if the events were read out successfully (even if there were no events to report).
*
* See icsneo_getErrors() for more information about the error system.
* See icsneo_getEvents() for more information about the event system.
*/
extern bool DLLExport icsneo_getDeviceErrors(const neodevice_t* device, neoerror_t* errors, size_t* size);
extern bool DLLExport icsneo_getDeviceEvents(const neodevice_t* device, neoevent_t* events, size_t* size);
/**
* \brief Read out the last error which occurred in API operation.
* \param[out] error A pointer to a buffer which a neoerror_t structure will be written to.
* \brief Read out the last error which occurred in API operation on this thread.
* \param[out] error A pointer to a buffer which a neoevent_t structure will be written to.
* \returns True if an error was read out.
*
* See icsneo_getErrors() for more information about the error system.
* All errors are stored on a per-thread basis, meaning that calling icsneo_getLastError() will return the last error that occured on the calling thread.
* Any errors can only be retrieved through this function, and NOT icsneo_getEvents() or similar! Only INFO and WARNING level events are accessible through those.
* Only the last error is stored, so the intention is for this function to be called immediately following another failed API call.
*
* This operation removes the returned error from the buffer, so subsequent calls to error functions will not inlcude the error.
*/
extern bool DLLExport icsneo_getLastError(neoerror_t* error);
/**
* \brief Discard all errors which have occurred in API operation.
*/
extern void DLLExport icsneo_discardAllErrors(void);
/**
* \brief Discard all errors which have occurred in API operation.
* \param[in] device A pointer to the neodevice_t structure specifying the device to discard errors for. NULL can be passed, which indicates that **ONLY** errors *not* associated with a device are desired (API errors).
*/
extern void DLLExport icsneo_discardDeviceErrors(const neodevice_t* device);
/**
* \brief Set the number of errors which will be held in the API managed buffer before icsneo::APIError::TooManyErrors
* \param[in] newLimit The new limit. Must be >10.
* The API error system is thread-safe. Only an API error which occurred on the current thread will be returned.
*
* If the error limit is reached, an icsneo::APIError::TooManyErrors will be flagged.
* See icsneo_getEvents() for more information about the event system.
*
* If the `newLimit` is smaller than the current error count,
* errors will be removed in order of increasing severity and decreasing age.
* This will also flag an icsneo::APIError::TooManyErrors.
* This operation removes the returned error from the buffer, so subsequent calls to error functions will not include the error.
*/
extern void DLLExport icsneo_setErrorLimit(size_t newLimit);
extern bool DLLExport icsneo_getLastError(neoevent_t* error);
/**
* \brief Set the number of errors which will be held in the API managed buffer before icsneo::APIError::TooManyErrors
* \brief Discard all events which have occurred in API operation. Does NOT discard any errors.
*/
extern void DLLExport icsneo_discardAllEvents(void);
/**
* \brief Discard all events which have occurred in API operation.
* \param[in] device A pointer to the neodevice_t structure specifying the device to discard events for. NULL can be passed, which indicates that **ONLY** events *not* associated with a device are desired (API events).
* Does NOT discard any errors (device or otherwise).
*/
extern void DLLExport icsneo_discardDeviceEvents(const neodevice_t* device);
/**
* \brief Set the number of events which will be held in the API managed buffer before icsneo::APIEvent::TooManyEvents
* \param[in] newLimit The new limit. Must be >10. 1 event slot is always reserved for a potential icsneo::APIEvent::TooManyEvents, so (newLimit - 1) other events can be stored.
*
* If the event limit is reached, an icsneo::APIEvent::TooManyEvents will be flagged.
*
* If the `newLimit` is smaller than the current event count,
* events will be removed in order of decreasing age.
* This will also flag an icsneo::APIEvent::TooManyEvents.
*/
extern void DLLExport icsneo_setEventLimit(size_t newLimit);
/**
* \brief Get the number of events which can be held in the API managed buffer
* \returns The current limit.
*
* If the error limit is reached, an icsneo::APIError::TooManyErrors will be flagged.
*/
extern size_t DLLExport icsneo_getErrorLimit(void);
extern size_t DLLExport icsneo_getEventLimit(void);
/**
* \brief Get the devices supported by the current version of the API
@@ -621,7 +699,7 @@ extern size_t DLLExport icsneo_getErrorLimit(void);
* A query for length (`devices == NULL`) will return false.
*
* If the count provided is not large enough, the output will be truncated.
* An icsneo::APIError::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* An icsneo::APIEvent::OutputTruncatedError will be available in icsneo_getLastError() in this case.
* True will still be returned.
*/
extern bool DLLExport icsneo_getSupportedDevices(devicetype_t* devices, size_t* count);
@@ -665,6 +743,9 @@ fn_icsneo_openDevice icsneo_openDevice;
typedef bool(*fn_icsneo_closeDevice)(const neodevice_t* device);
fn_icsneo_closeDevice icsneo_closeDevice;
typedef bool(*fn_icsneo_isOpen)(const neodevice_t* device);
fn_icsneo_isOpen icsneo_isOpen;
typedef bool(*fn_icsneo_goOnline)(const neodevice_t* device);
fn_icsneo_goOnline icsneo_goOnline;
@@ -680,6 +761,9 @@ fn_icsneo_enableMessagePolling icsneo_enableMessagePolling;
typedef bool(*fn_icsneo_disableMessagePolling)(const neodevice_t* device);
fn_icsneo_disableMessagePolling icsneo_disableMessagePolling;
typedef bool(*fn_icsneo_isMessagePollingEnabled)(const neodevice_t* device);
fn_icsneo_isMessagePollingEnabled icsneo_isMessagePollingEnabled;
typedef bool(*fn_icsneo_getMessages)(const neodevice_t* device, neomessage_t* messages, size_t* items, uint64_t timeout);
fn_icsneo_getMessages icsneo_getMessages;
@@ -689,6 +773,12 @@ fn_icsneo_getPollingMessageLimit icsneo_getPollingMessageLimit;
typedef bool(*fn_icsneo_setPollingMessageLimit)(const neodevice_t* device, size_t newLimit);
fn_icsneo_setPollingMessageLimit icsneo_setPollingMessageLimit;
typedef int(*fn_icsneo_addMessageCallback)(const neodevice_t* device, void (*callback)(neomessage_t), void*);
fn_icsneo_addMessageCallback icsneo_addMessageCallback;
typedef bool(*fn_icsneo_removeMessageCallback)(const neodevice_t* device, int id);
fn_icsneo_removeMessageCallback icsneo_removeMessageCallback;
typedef bool(*fn_icsneo_getProductName)(const neodevice_t* device, char* str, size_t* maxLength);
fn_icsneo_getProductName icsneo_getProductName;
@@ -707,7 +797,7 @@ fn_icsneo_settingsApplyDefaults icsneo_settingsApplyDefaults;
typedef bool(*fn_icsneo_settingsApplyDefaultsTemporary)(const neodevice_t* device);
fn_icsneo_settingsApplyDefaultsTemporary icsneo_settingsApplyDefaultsTemporary;
typedef size_t(*fn_icsneo_settingsReadStructure)(const neodevice_t* device, void* structure, size_t structureSize);
typedef int(*fn_icsneo_settingsReadStructure)(const neodevice_t* device, void* structure, size_t structureSize);
fn_icsneo_settingsReadStructure icsneo_settingsReadStructure;
typedef bool(*fn_icsneo_settingsApplyStructure)(const neodevice_t* device, const void* structure, size_t structureSize);
@@ -734,32 +824,41 @@ fn_icsneo_transmit icsneo_transmit;
typedef bool(*fn_icsneo_transmitMessages)(const neodevice_t* device, const neomessage_t* messages, size_t count);
fn_icsneo_transmitMessages icsneo_transmitMessages;
typedef bool(*fn_icsneo_setWriteBlocks)(const neodevice_t* device, bool blocks);
fn_icsneo_setWriteBlocks icsneo_setWriteBlocks;
typedef bool(*fn_icsneo_describeDevice)(const neodevice_t* device, char* str, size_t* maxLength);
fn_icsneo_describeDevice icsneo_describeDevice;
typedef neoversion_t(*fn_icsneo_getVersion)(void);
fn_icsneo_getVersion icsneo_getVersion;
typedef bool(*fn_icsneo_getErrors)(neoerror_t* errors, size_t* size);
fn_icsneo_getErrors icsneo_getErrors;
typedef int(*fn_icsneo_addEventCallback)(void (*callback)(neoevent_t), void*);
fn_icsneo_addEventCallback icsneo_addEventCallback;
typedef bool(*fn_icsneo_getDeviceErrors)(const neodevice_t* device, neoerror_t* errors, size_t* size);
fn_icsneo_getDeviceErrors icsneo_getDeviceErrors;
typedef bool(*fn_icsneo_removeEventCallback)(int id);
fn_icsneo_removeEventCallback icsneo_removeEventCallback;
typedef bool(*fn_icsneo_getLastError)(neoerror_t* error);
typedef bool(*fn_icsneo_getEvents)(neoevent_t* events, size_t* size);
fn_icsneo_getEvents icsneo_getEvents;
typedef bool(*fn_icsneo_getDeviceEvents)(const neodevice_t* device, neoevent_t* events, size_t* size);
fn_icsneo_getDeviceEvents icsneo_getDeviceEvents;
typedef bool(*fn_icsneo_getLastError)(neoevent_t* error);
fn_icsneo_getLastError icsneo_getLastError;
typedef void(*fn_icsneo_discardAllErrors)(void);
fn_icsneo_discardAllErrors icsneo_discardAllErrors;
typedef void(*fn_icsneo_discardAllEvents)(void);
fn_icsneo_discardAllEvents icsneo_discardAllEvents;
typedef void(*fn_icsneo_discardDeviceErrors)(const neodevice_t* device);
fn_icsneo_discardDeviceErrors icsneo_discardDeviceErrors;
typedef void(*fn_icsneo_discardDeviceEvents)(const neodevice_t* device);
fn_icsneo_discardDeviceEvents icsneo_discardDeviceEvents;
typedef void(*fn_icsneo_setErrorLimit)(size_t newLimit);
fn_icsneo_setErrorLimit icsneo_setErrorLimit;
typedef void(*fn_icsneo_setEventLimit)(size_t newLimit);
fn_icsneo_setEventLimit icsneo_setEventLimit;
typedef size_t(*fn_icsneo_getErrorLimit)(void);
fn_icsneo_getErrorLimit icsneo_getErrorLimit;
typedef size_t(*fn_icsneo_getEventLimit)(void);
fn_icsneo_getEventLimit icsneo_getEventLimit;
#define ICSNEO_IMPORT(func) func = (fn_##func)icsneo_dynamicLibraryGetFunction(icsneo_libraryHandle, #func)
#define ICSNEO_IMPORTASSERT(func) if((ICSNEO_IMPORT(func)) == NULL) return 3
@@ -782,14 +881,18 @@ int icsneo_init() {
ICSNEO_IMPORTASSERT(icsneo_isValidNeoDevice);
ICSNEO_IMPORTASSERT(icsneo_openDevice);
ICSNEO_IMPORTASSERT(icsneo_closeDevice);
ICSNEO_IMPORTASSERT(icsneo_isOpen);
ICSNEO_IMPORTASSERT(icsneo_goOnline);
ICSNEO_IMPORTASSERT(icsneo_goOffline);
ICSNEO_IMPORTASSERT(icsneo_isOnline);
ICSNEO_IMPORTASSERT(icsneo_enableMessagePolling);
ICSNEO_IMPORTASSERT(icsneo_disableMessagePolling);
ICSNEO_IMPORTASSERT(icsneo_isMessagePollingEnabled);
ICSNEO_IMPORTASSERT(icsneo_getMessages);
ICSNEO_IMPORTASSERT(icsneo_getPollingMessageLimit);
ICSNEO_IMPORTASSERT(icsneo_setPollingMessageLimit);
ICSNEO_IMPORTASSERT(icsneo_addMessageCallback);
ICSNEO_IMPORTASSERT(icsneo_removeMessageCallback);
ICSNEO_IMPORTASSERT(icsneo_getProductName);
ICSNEO_IMPORTASSERT(icsneo_settingsRefresh);
ICSNEO_IMPORTASSERT(icsneo_settingsApply);
@@ -805,15 +908,18 @@ int icsneo_init() {
ICSNEO_IMPORTASSERT(icsneo_setFDBaudrate);
ICSNEO_IMPORTASSERT(icsneo_transmit);
ICSNEO_IMPORTASSERT(icsneo_transmitMessages);
ICSNEO_IMPORTASSERT(icsneo_setWriteBlocks);
ICSNEO_IMPORTASSERT(icsneo_describeDevice);
ICSNEO_IMPORTASSERT(icsneo_getVersion);
ICSNEO_IMPORTASSERT(icsneo_getErrors);
ICSNEO_IMPORTASSERT(icsneo_getDeviceErrors);
ICSNEO_IMPORTASSERT(icsneo_addEventCallback);
ICSNEO_IMPORTASSERT(icsneo_removeEventCallback);
ICSNEO_IMPORTASSERT(icsneo_getEvents);
ICSNEO_IMPORTASSERT(icsneo_getDeviceEvents);
ICSNEO_IMPORTASSERT(icsneo_getLastError);
ICSNEO_IMPORTASSERT(icsneo_discardAllErrors);
ICSNEO_IMPORTASSERT(icsneo_discardDeviceErrors);
ICSNEO_IMPORTASSERT(icsneo_setErrorLimit);
ICSNEO_IMPORTASSERT(icsneo_getErrorLimit);
ICSNEO_IMPORTASSERT(icsneo_discardAllEvents);
ICSNEO_IMPORTASSERT(icsneo_discardDeviceEvents);
ICSNEO_IMPORTASSERT(icsneo_setEventLimit);
ICSNEO_IMPORTASSERT(icsneo_getEventLimit);
icsneo_initialized = true;
return 0;
+10 -10
View File
@@ -6,7 +6,7 @@
#include "icsneo/device/device.h"
#include "icsneo/api/version.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h"
@@ -16,15 +16,15 @@ namespace icsneo {
std::vector<std::shared_ptr<Device>> FindAllDevices();
std::vector<DeviceType> GetSupportedDevices();
size_t ErrorCount(ErrorFilter filter = ErrorFilter());
std::vector<APIError> GetErrors(ErrorFilter filter, size_t max = 0);
std::vector<APIError> GetErrors(size_t max = 0, ErrorFilter filter = ErrorFilter());
void GetErrors(std::vector<APIError>& errors, ErrorFilter filter, size_t max = 0);
void GetErrors(std::vector<APIError>& errors, size_t max = 0, ErrorFilter filter = ErrorFilter());
bool GetLastError(APIError& error, ErrorFilter filter = ErrorFilter());
void DiscardErrors(ErrorFilter filter = ErrorFilter());
void SetErrorLimit(size_t newLimit);
size_t GetErrorLimit();
size_t EventCount(EventFilter filter = EventFilter());
std::vector<APIEvent> GetEvents(EventFilter filter, size_t max = 0);
std::vector<APIEvent> GetEvents(size_t max = 0, EventFilter filter = EventFilter());
void GetEvents(std::vector<APIEvent>& events, EventFilter filter, size_t max = 0);
void GetEvents(std::vector<APIEvent>& events, size_t max = 0, EventFilter filter = EventFilter());
APIEvent GetLastError();
void DiscardEvents(EventFilter filter = EventFilter());
void SetEventLimit(size_t newLimit);
size_t GetEventLimit();
}
@@ -1,6 +1,6 @@
#ifndef __DYNAMICLIB_DARWIN_H_
#define __DYNAMICLIB_DARWIN_H_
#define icsneo_dynamicLibraryLoad() dlopen("/Users/paulywog/Code/icsneonext/build/libicsneoc.dylib", RTLD_LAZY)
#define icsneo_dynamicLibraryLoad() dlopen("libicsneoc.dylib", RTLD_LAZY)
#endif
+18 -18
View File
@@ -1,23 +1,23 @@
#ifndef __DEVICES_POSIX_H_
#define __DEVICES_POSIX_H_
#include "icsneo/device/neoobd2pro/neoobd2pro.h"
#include "icsneo/device/neoobd2sim/neoobd2sim.h"
#include "icsneo/device/neovifire/neovifire.h"
//#include "icsneo/device/neovifire2/neovifire2eth.h"
#include "icsneo/device/neovifire2/neovifire2usb.h"
#include "icsneo/device/plasion/neoviion.h"
#include "icsneo/device/plasion/neoviplasma.h"
//#include "icsneo/device/radgalaxy/radgalaxy.h"
#include "icsneo/device/radpluto/radplutousb.h"
//#include "icsneo/device/radstar2/radstar2eth.h"
#include "icsneo/device/radstar2/radstar2usb.h"
#include "icsneo/device/radsupermoon/radsupermoon.h"
#include "icsneo/device/valuecan3/valuecan3.h"
#include "icsneo/device/valuecan4/valuecan4-1.h"
#include "icsneo/device/valuecan4/valuecan4-2.h"
#include "icsneo/device/valuecan4/valuecan4-2el.h"
#include "icsneo/device/valuecan4/valuecan4-4.h"
#include "icsneo/device/vividcan/vividcan.h"
#include "icsneo/device/tree/neoobd2pro/neoobd2pro.h"
#include "icsneo/device/tree/neoobd2sim/neoobd2sim.h"
#include "icsneo/device/tree/neovifire/neovifire.h"
//#include "icsneo/device/tree/neovifire2/neovifire2eth.h"
#include "icsneo/device/tree/neovifire2/neovifire2usb.h"
#include "icsneo/device/tree/plasion/neoviion.h"
#include "icsneo/device/tree/plasion/neoviplasma.h"
//#include "icsneo/device/tree/radgalaxy/radgalaxy.h"
#include "icsneo/device/tree/radpluto/radplutousb.h"
//#include "icsneo/device/tree/radstar2/radstar2eth.h"
#include "icsneo/device/tree/radstar2/radstar2usb.h"
#include "icsneo/device/tree/radsupermoon/radsupermoon.h"
#include "icsneo/device/tree/valuecan3/valuecan3.h"
#include "icsneo/device/tree/valuecan4/valuecan4-1.h"
#include "icsneo/device/tree/valuecan4/valuecan4-2.h"
#include "icsneo/device/tree/valuecan4/valuecan4-2el.h"
#include "icsneo/device/tree/valuecan4/valuecan4-4.h"
#include "icsneo/device/tree/vividcan/vividcan.h"
#endif
+3 -2
View File
@@ -8,7 +8,7 @@
#include "icsneo/device/neodevice.h"
#include "icsneo/communication/icommunication.h"
#include "icsneo/third-party/concurrentqueue/blockingconcurrentqueue.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
namespace icsneo {
@@ -16,7 +16,7 @@ class FTDI : public ICommunication {
public:
static std::vector<neodevice_t> FindByProduct(int product);
FTDI(const device_errorhandler_t& err, neodevice_t& forDevice);
FTDI(const device_eventhandler_t& err, neodevice_t& forDevice);
~FTDI() { close(); }
bool open();
bool close();
@@ -41,6 +41,7 @@ private:
int read(uint8_t* data, size_t size) { return ftdi_read_data(context, data, (int)size); }
int write(const uint8_t* data, size_t size) { return ftdi_write_data(context, data, (int)size); }
int setBaudrate(int baudrate) { return ftdi_set_baudrate(context, baudrate); }
int setLatencyTimer(uint8_t latency) { return ftdi_set_latency_timer(context, latency); }
bool setReadTimeout(int timeout) { if(context == nullptr) return false; context->usb_read_timeout = timeout; return true; }
bool setWriteTimeout(int timeout) { if(context == nullptr) return false; context->usb_write_timeout = timeout; return true; }
private:
+2 -2
View File
@@ -3,7 +3,7 @@
#include "icsneo/device/neodevice.h"
#include "icsneo/communication/icommunication.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include <string>
#include <pcap.h>
@@ -21,7 +21,7 @@ public:
static std::string GetEthDevSerialFromMacAddress(uint8_t product, uint16_t macSerial);
static bool IsHandleValid(neodevice_handle_t handle);
PCAP(device_errorhandler_t err, neodevice_t& forDevice);
PCAP(device_eventhandler_t err, neodevice_t& forDevice);
bool open();
bool isOpen();
bool close();
+2 -2
View File
@@ -3,7 +3,7 @@
#include "icsneo/communication/icommunication.h"
#include "icsneo/device/neodevice.h"
#include "icsneo/api/errormanager.h"
#include "icsneo/api/eventmanager.h"
#include <chrono>
#include <stdint.h>
@@ -11,7 +11,7 @@ namespace icsneo {
class STM32 : public ICommunication {
public:
STM32(const device_errorhandler_t& err, neodevice_t& forDevice) : ICommunication(err), device(forDevice) {}
STM32(const device_eventhandler_t& err, neodevice_t& forDevice) : ICommunication(err), device(forDevice) {}
static std::vector<neodevice_t> FindByProduct(int product);
bool open();

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