Merge branch 'v0.3.0-dev' into VUP-7
commit
0633bdbdaa
|
|
@ -0,0 +1,51 @@
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- test
|
||||||
|
|
||||||
|
build windows/x64:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- CMD.EXE /C ci\build-windows64.bat
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
expire_in: 3 days
|
||||||
|
tags:
|
||||||
|
- icsneo-windows
|
||||||
|
|
||||||
|
test windows/x64:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- build\libicsneo-tests.exe
|
||||||
|
dependencies:
|
||||||
|
- build windows/x64
|
||||||
|
needs:
|
||||||
|
- build windows/x64
|
||||||
|
tags:
|
||||||
|
- icsneo-windows
|
||||||
|
timeout: 3m
|
||||||
|
|
||||||
|
build windows/x86:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- CMD.EXE /C ci\build-windows32.bat
|
||||||
|
artifacts:
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- build
|
||||||
|
expire_in: 3 days
|
||||||
|
tags:
|
||||||
|
- icsneo-windows
|
||||||
|
|
||||||
|
test windows/x86:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- build\libicsneo-tests.exe
|
||||||
|
dependencies:
|
||||||
|
- build windows/x86
|
||||||
|
needs:
|
||||||
|
- build windows/x86
|
||||||
|
tags:
|
||||||
|
- icsneo-windows
|
||||||
|
timeout: 3m
|
||||||
128
CMakeLists.txt
128
CMakeLists.txt
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.2)
|
cmake_minimum_required(VERSION 3.2)
|
||||||
project(libicsneo VERSION 0.2.0)
|
project(libicsneo VERSION 0.3.0)
|
||||||
|
|
||||||
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
|
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
|
||||||
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
|
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
|
||||||
|
|
@ -9,7 +9,18 @@ option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
|
||||||
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
|
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
|
||||||
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
|
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
# Device Drivers
|
||||||
|
# You almost certainly don't want firmio for your build,
|
||||||
|
# it is only relevant for communication between Linux and
|
||||||
|
# CoreMini from the onboard processor of the device.
|
||||||
|
option(LIBICSNEO_ENABLE_FIRMIO "Enable communication between Linux and CoreMini within the same device" OFF)
|
||||||
|
option(LIBICSNEO_ENABLE_RAW_ETHERNET "Enable devices which communicate over raw ethernet" ON)
|
||||||
|
option(LIBICSNEO_ENABLE_CDCACM "Enable devices which communicate over USB CDC ACM" ON)
|
||||||
|
option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX" ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
|
@ -84,30 +95,61 @@ endif()
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||||
set(PLATFORM_SRC
|
set(PLATFORM_SRC
|
||||||
platform/windows/pcap.cpp
|
|
||||||
platform/windows/registry.cpp
|
platform/windows/registry.cpp
|
||||||
platform/windows/vcp.cpp
|
|
||||||
platform/windows/internal/pcapdll.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
|
||||||
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/windows/pcap.cpp
|
||||||
|
platform/windows/internal/pcapdll.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
|
||||||
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/windows/vcp.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
else() # Darwin or Linux
|
else() # Darwin or Linux
|
||||||
set(PLATFORM_SRC
|
set(PLATFORM_SRC)
|
||||||
platform/posix/ftdi.cpp
|
|
||||||
platform/posix/pcap.cpp
|
if(LIBICSNEO_ENABLE_FIRMIO)
|
||||||
platform/posix/cdcacm.cpp
|
|
||||||
)
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
|
||||||
list(APPEND PLATFORM_SRC
|
list(APPEND PLATFORM_SRC
|
||||||
platform/posix/darwin/cdcacmdarwin.cpp
|
platform/posix/firmio.cpp
|
||||||
)
|
)
|
||||||
else() # Linux or other
|
endif()
|
||||||
|
|
||||||
|
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
|
||||||
list(APPEND PLATFORM_SRC
|
list(APPEND PLATFORM_SRC
|
||||||
platform/posix/linux/cdcacmlinux.cpp
|
platform/posix/pcap.cpp
|
||||||
)
|
)
|
||||||
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
endif()
|
||||||
message(WARNING
|
|
||||||
"There is no platform port defined for ${CMAKE_SYSTEM_NAME}!\n"
|
if(LIBICSNEO_ENABLE_FTDI)
|
||||||
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly."
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/posix/ftdi.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LIBICSNEO_ENABLE_CDCACM)
|
||||||
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/posix/cdcacm.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||||
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/posix/darwin/cdcacmdarwin.cpp
|
||||||
)
|
)
|
||||||
|
else() # Linux or other
|
||||||
|
list(APPEND PLATFORM_SRC
|
||||||
|
platform/posix/linux/cdcacmlinux.cpp
|
||||||
|
)
|
||||||
|
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
|
message(WARNING
|
||||||
|
"There is no CDCACM platform port defined for ${CMAKE_SYSTEM_NAME}!\n"
|
||||||
|
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly."
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -127,11 +169,14 @@ endforeach()
|
||||||
set(SRC_FILES
|
set(SRC_FILES
|
||||||
communication/message/flexray/control/flexraycontrolmessage.cpp
|
communication/message/flexray/control/flexraycontrolmessage.cpp
|
||||||
communication/message/neomessage.cpp
|
communication/message/neomessage.cpp
|
||||||
|
communication/message/ethphymessage.cpp
|
||||||
communication/packet/flexraypacket.cpp
|
communication/packet/flexraypacket.cpp
|
||||||
communication/packet/canpacket.cpp
|
communication/packet/canpacket.cpp
|
||||||
communication/packet/ethernetpacket.cpp
|
communication/packet/ethernetpacket.cpp
|
||||||
communication/packet/versionpacket.cpp
|
communication/packet/versionpacket.cpp
|
||||||
communication/packet/iso9141packet.cpp
|
communication/packet/iso9141packet.cpp
|
||||||
|
communication/packet/ethphyregpacket.cpp
|
||||||
|
communication/packet/logicaldiskinfopacket.cpp
|
||||||
communication/decoder.cpp
|
communication/decoder.cpp
|
||||||
communication/encoder.cpp
|
communication/encoder.cpp
|
||||||
communication/ethernetpacketizer.cpp
|
communication/ethernetpacketizer.cpp
|
||||||
|
|
@ -144,6 +189,14 @@ set(SRC_FILES
|
||||||
device/idevicesettings.cpp
|
device/idevicesettings.cpp
|
||||||
device/devicefinder.cpp
|
device/devicefinder.cpp
|
||||||
device/device.cpp
|
device/device.cpp
|
||||||
|
device/neodevice.cpp
|
||||||
|
disk/diskreaddriver.cpp
|
||||||
|
disk/diskwritedriver.cpp
|
||||||
|
disk/nulldiskdriver.cpp
|
||||||
|
disk/neomemorydiskdriver.cpp
|
||||||
|
disk/plasiondiskreaddriver.cpp
|
||||||
|
disk/extextractordiskreaddriver.cpp
|
||||||
|
disk/fat.cpp
|
||||||
${PLATFORM_SRC}
|
${PLATFORM_SRC}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -208,6 +261,22 @@ set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||||
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
|
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
|
||||||
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
|
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
|
||||||
|
if(LIBICSNEO_ENABLE_FIRMIO)
|
||||||
|
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FIRMIO)
|
||||||
|
endif()
|
||||||
|
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
|
||||||
|
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_RAW_ETHERNET)
|
||||||
|
endif()
|
||||||
|
if(LIBICSNEO_ENABLE_CDCACM)
|
||||||
|
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
|
||||||
|
endif()
|
||||||
|
if(LIBICSNEO_ENABLE_FTDI)
|
||||||
|
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# fatfs
|
||||||
|
add_subdirectory(third-party/fatfs)
|
||||||
|
target_link_libraries(icsneocpp PRIVATE fatfs)
|
||||||
|
|
||||||
# libftdi
|
# libftdi
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
|
|
@ -220,7 +289,7 @@ if(NOT WIN32)
|
||||||
set(FTDIPP OFF CACHE INTERNAL "")
|
set(FTDIPP OFF CACHE INTERNAL "")
|
||||||
set(FTDI_EEPROM OFF CACHE INTERNAL "")
|
set(FTDI_EEPROM OFF CACHE INTERNAL "")
|
||||||
add_subdirectory(third-party/libftdi)
|
add_subdirectory(third-party/libftdi)
|
||||||
include_directories(${LIBUSB_INCLUDE_DIR})
|
target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
|
|
||||||
# winpcap
|
# winpcap
|
||||||
|
|
@ -289,6 +358,7 @@ if(NOT WIN32)
|
||||||
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
|
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
|
||||||
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||||
find_package(PCAP REQUIRED)
|
find_package(PCAP REQUIRED)
|
||||||
|
target_include_directories(icsneocpp PUBLIC ${PCAP_INCLUDE_DIR})
|
||||||
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
|
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -298,22 +368,30 @@ if(LIBICSNEO_BUILD_TESTS)
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(third-party/googletest-master)
|
if (NOT TARGET gtest)
|
||||||
|
add_subdirectory(third-party/googletest-master)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (CMAKE_VERSION VERSION_LESS 2.8.11)
|
if (CMAKE_VERSION VERSION_LESS 2.8.11)
|
||||||
include_directories("${gtest_SOURCE_DIR}/include")
|
include_directories("${gtest_SOURCE_DIR}/include")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(runTests test/main.cpp test/eventmanagertest.cpp)
|
add_executable(libicsneo-tests
|
||||||
|
test/main.cpp
|
||||||
|
test/diskdriverreadtest.cpp
|
||||||
|
test/diskdriverwritetest.cpp
|
||||||
|
test/eventmanagertest.cpp
|
||||||
|
test/ethernetpacketizertest.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(runTests gtest gtest_main)
|
target_link_libraries(libicsneo-tests gtest gtest_main)
|
||||||
target_link_libraries(runTests icsneocpp)
|
target_link_libraries(libicsneo-tests icsneocpp)
|
||||||
|
|
||||||
target_include_directories(runTests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
target_include_directories(libicsneo-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
add_test(NAME testSuite COMMAND runTests)
|
add_test(NAME libicsneo-test-suite COMMAND libicsneo-tests)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
|
|
|
||||||
|
|
@ -453,7 +453,10 @@ bool icsneo_transmit(const neodevice_t* device, const neomessage_t* message) {
|
||||||
if(!icsneo_isValidNeoDevice(device))
|
if(!icsneo_isValidNeoDevice(device))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return device->device->transmit(CreateMessageFromNeoMessage(message));
|
if(auto frame = std::dynamic_pointer_cast<icsneo::Frame>(CreateMessageFromNeoMessage(message)))
|
||||||
|
return device->device->transmit(frame);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool icsneo_transmitMessages(const neodevice_t* device, const neomessage_t* messages, size_t count) {
|
bool icsneo_transmitMessages(const neodevice_t* device, const neomessage_t* messages, size_t count) {
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ static constexpr const char* DEVICE_NOT_CURRENTLY_POLLING = "The device is not c
|
||||||
static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network.";
|
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.";
|
static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long.";
|
||||||
static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present.";
|
static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present.";
|
||||||
|
static constexpr const char* TIMEOUT = "The timeout was reached.";
|
||||||
|
|
||||||
// Device Errors
|
// 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* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
|
||||||
|
|
@ -102,6 +103,12 @@ static constexpr const char* ONLINE_NOT_SUPPORTED = "This device does not suppor
|
||||||
static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination.";
|
static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination.";
|
||||||
static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device.";
|
static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device.";
|
||||||
static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled.";
|
static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled.";
|
||||||
|
static constexpr const char* ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE = "Ethernet PHY register control is not available for this device.";
|
||||||
|
static constexpr const char* DISK_NOT_SUPPORTED = "This device does not support accessing the specified disk.";
|
||||||
|
static constexpr const char* EOF_REACHED = "The requested length exceeds the available data from this disk.";
|
||||||
|
static constexpr const char* SETTINGS_DEFAULTS_USED = "The device settings could not be loaded, the default settings have been applied.";
|
||||||
|
static constexpr const char* ATOMIC_OPERATION_RETRIED = "An operation failed to be atomically completed, but will be retried.";
|
||||||
|
static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An ideally-atomic operation was completed nonatomically.";
|
||||||
|
|
||||||
// Transport Errors
|
// Transport Errors
|
||||||
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
||||||
|
|
@ -149,6 +156,8 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||||
return MESSAGE_MAX_LENGTH_EXCEEDED;
|
return MESSAGE_MAX_LENGTH_EXCEEDED;
|
||||||
case Type::ValueNotYetPresent:
|
case Type::ValueNotYetPresent:
|
||||||
return VALUE_NOT_YET_PRESENT;
|
return VALUE_NOT_YET_PRESENT;
|
||||||
|
case Type::Timeout:
|
||||||
|
return TIMEOUT;
|
||||||
|
|
||||||
// Device Errors
|
// Device Errors
|
||||||
case Type::PollingMessageOverflow:
|
case Type::PollingMessageOverflow:
|
||||||
|
|
@ -211,6 +220,18 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||||
return NO_SERIAL_NUMBER_12V;
|
return NO_SERIAL_NUMBER_12V;
|
||||||
case Type::NoSerialNumberFW12V:
|
case Type::NoSerialNumberFW12V:
|
||||||
return NO_SERIAL_NUMBER_FW_12V;
|
return NO_SERIAL_NUMBER_FW_12V;
|
||||||
|
case Type::EthPhyRegisterControlNotAvailable:
|
||||||
|
return ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE;
|
||||||
|
case Type::DiskNotSupported:
|
||||||
|
return DISK_NOT_SUPPORTED;
|
||||||
|
case Type::EOFReached:
|
||||||
|
return EOF_REACHED;
|
||||||
|
case Type::SettingsDefaultsUsed:
|
||||||
|
return SETTINGS_DEFAULTS_USED;
|
||||||
|
case Type::AtomicOperationRetried:
|
||||||
|
return ATOMIC_OPERATION_RETRIED;
|
||||||
|
case Type::AtomicOperationCompletedNonatomically:
|
||||||
|
return ATOMIC_OPERATION_COMPLETED_NONATOMICALLY;
|
||||||
|
|
||||||
// Transport Errors
|
// Transport Errors
|
||||||
case Type::FailedToRead:
|
case Type::FailedToRead:
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,99 @@ EventManager& EventManager::GetInstance() {
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventManager::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});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::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::lock_guard<std::mutex> eventsLock(eventsMutex);
|
||||||
|
addEventInternal(event);
|
||||||
|
} // free the lock so that callbacks may modify events
|
||||||
|
runCallbacks(event);
|
||||||
|
} else {
|
||||||
|
std::lock_guard<std::mutex> errorsLock(errorsMutex);
|
||||||
|
lastUserErrors[std::this_thread::get_id()] = event;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> eventsLock(eventsMutex);
|
||||||
|
addEventInternal(event);
|
||||||
|
} // free the lock so that callbacks may modify events
|
||||||
|
runCallbacks(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::addEventInternal(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::runCallbacks(APIEvent event) {
|
||||||
|
std::lock_guard<std::mutex> lk(callbacksMutex);
|
||||||
|
for(auto& i : callbacks)
|
||||||
|
i.second.callIfMatch(std::make_shared<APIEvent>(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::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())
|
||||||
|
addEventInternal(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
|
||||||
|
}
|
||||||
|
|
||||||
void EventManager::ResetInstance() {
|
void EventManager::ResetInstance() {
|
||||||
std::lock_guard<std::mutex> eventsLock(eventsMutex);
|
std::lock_guard<std::mutex> eventsLock(eventsMutex);
|
||||||
std::lock_guard<std::mutex> errorsLock(errorsMutex);
|
std::lock_guard<std::mutex> errorsLock(errorsMutex);
|
||||||
|
|
@ -98,7 +191,7 @@ void EventManager::discard(EventFilter filter) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t EventManager::count_internal(EventFilter filter) const {
|
size_t EventManager::countInternal(EventFilter filter) const {
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for(auto& event : events)
|
for(auto& event : events)
|
||||||
if(filter.match(event))
|
if(filter.match(event))
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -24,5 +24,5 @@ int LegacyDLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned i
|
||||||
neodevice_t* device = (neodevice_t*)hObject;
|
neodevice_t* device = (neodevice_t*)hObject;
|
||||||
if(device->device->getCurrentMessageCount() != 0)
|
if(device->device->getCurrentMessageCount() != 0)
|
||||||
return true;
|
return true;
|
||||||
return bool(device->device->com->waitForMessageSync(MessageFilter(), std::chrono::milliseconds(iTimeOut)));
|
return bool(device->device->com->waitForMessageSync({}, std::chrono::milliseconds(iTimeOut)));
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
REM clean intermediate directories
|
||||||
|
rmdir /s /q build
|
||||||
|
mkdir build
|
||||||
|
|
||||||
|
REM build
|
||||||
|
cd build
|
||||||
|
set CFLAGS=/WX
|
||||||
|
set CXXFLAGS=/WX
|
||||||
|
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_TESTS=ON ..
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
cmake --build .
|
||||||
|
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
call "%VCVARS32%"
|
||||||
|
call "ci\build-windows.bat"
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
call "%VCVARS64%"
|
||||||
|
call "ci\build-windows.bat"
|
||||||
|
|
@ -79,6 +79,21 @@ bool Communication::sendCommand(Command cmd, std::vector<uint8_t> arguments) {
|
||||||
return sendPacket(packet);
|
return sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Communication::sendCommand(ExtendedCommand cmd, std::vector<uint8_t> arguments) {
|
||||||
|
const auto size = arguments.size();
|
||||||
|
if (size > std::numeric_limits<uint16_t>::max())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
arguments.insert(arguments.begin(), {
|
||||||
|
uint8_t(uint16_t(cmd) & 0xff),
|
||||||
|
uint8_t((uint16_t(cmd) >> 8) & 0xff),
|
||||||
|
uint8_t(size & 0xff),
|
||||||
|
uint8_t((size >> 8) & 0xff)
|
||||||
|
});
|
||||||
|
|
||||||
|
return sendCommand(Command::Extended, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
bool Communication::redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo) {
|
bool Communication::redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo) {
|
||||||
if(redirectingRead)
|
if(redirectingRead)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -97,9 +112,10 @@ void Communication::clearRedirectRead() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
|
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
|
||||||
|
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings);
|
||||||
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
||||||
return sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ });
|
return sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ });
|
||||||
}, MessageFilter(Network::NetID::ReadSettings), timeout);
|
}, filter, timeout);
|
||||||
if(!msg)
|
if(!msg)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -109,35 +125,38 @@ bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::mil
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gsmsg->response != ReadSettingsMessage::Response::OK) {
|
if(gsmsg->response == ReadSettingsMessage::Response::OKDefaultsUsed) {
|
||||||
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
|
report(APIEvent::Type::SettingsDefaultsUsed, APIEvent::Severity::EventInfo);
|
||||||
|
} else if(gsmsg->response != ReadSettingsMessage::Response::OK) {
|
||||||
|
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = std::move(msg->data);
|
data = std::move(gsmsg->data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) {
|
std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) {
|
||||||
|
static const std::shared_ptr<MessageFilter> filter = std::make_shared<Main51MessageFilter>(Command::RequestSerialNumber);
|
||||||
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
||||||
return sendCommand(Command::RequestSerialNumber);
|
return sendCommand(Command::RequestSerialNumber);
|
||||||
}, Main51MessageFilter(Command::RequestSerialNumber), timeout);
|
}, filter, timeout);
|
||||||
if(!msg) // Did not receive a message
|
if(!msg) // Did not receive a message
|
||||||
return std::shared_ptr<SerialNumberMessage>();
|
return std::shared_ptr<SerialNumberMessage>();
|
||||||
|
|
||||||
auto m51 = std::dynamic_pointer_cast<Main51Message>(msg);
|
auto m51 = std::dynamic_pointer_cast<Main51Message>(msg);
|
||||||
if(!m51) // Could not upcast for some reason
|
if(!m51) // Could not upcast for some reason
|
||||||
return std::shared_ptr<SerialNumberMessage>();
|
return std::shared_ptr<SerialNumberMessage>();
|
||||||
|
|
||||||
return std::dynamic_pointer_cast<SerialNumberMessage>(m51);
|
return std::dynamic_pointer_cast<SerialNumberMessage>(m51);
|
||||||
}
|
}
|
||||||
|
|
||||||
optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersionsSync(std::chrono::milliseconds timeout) {
|
optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersionsSync(std::chrono::milliseconds timeout) {
|
||||||
|
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::DeviceVersion);
|
||||||
std::vector< optional<DeviceAppVersion> > ret;
|
std::vector< optional<DeviceAppVersion> > ret;
|
||||||
|
|
||||||
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
||||||
return sendCommand(Command::GetMainVersion);
|
return sendCommand(Command::GetMainVersion);
|
||||||
}, Main51MessageFilter(Command::GetMainVersion), timeout);
|
}, filter, timeout);
|
||||||
if(!msg) // Did not receive a message
|
if(!msg) // Did not receive a message
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
|
|
@ -145,24 +164,35 @@ optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersions
|
||||||
if(!ver) // Could not upcast for some reason
|
if(!ver) // Could not upcast for some reason
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
if(!ver->MainChip || ver->Versions.size() != 1)
|
if(ver->ForChip != VersionMessage::MainChip || ver->Versions.size() != 1)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
ret.push_back(ver->Versions.front());
|
ret.push_back(ver->Versions.front());
|
||||||
|
|
||||||
msg = waitForMessageSync([this]() {
|
msg = waitForMessageSync([this]() {
|
||||||
return sendCommand(Command::GetSecondaryVersions);
|
return sendCommand(Command::GetSecondaryVersions);
|
||||||
}, Main51MessageFilter(Command::GetSecondaryVersions), timeout);
|
}, filter, timeout);
|
||||||
if(msg) { // This one is allowed to fail
|
if(msg) { // This one is allowed to fail
|
||||||
ver = std::dynamic_pointer_cast<VersionMessage>(msg);
|
ver = std::dynamic_pointer_cast<VersionMessage>(msg);
|
||||||
if(ver && !ver->MainChip) {
|
if(ver && ver->ForChip != VersionMessage::MainChip)
|
||||||
ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end());
|
ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<LogicalDiskInfoMessage> Communication::getLogicalDiskInfoSync(std::chrono::milliseconds timeout) {
|
||||||
|
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::LogicalDiskInfo);
|
||||||
|
|
||||||
|
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
|
||||||
|
return sendCommand(Command::GetLogicalDiskInfo);
|
||||||
|
}, filter, timeout);
|
||||||
|
if(!msg) // Did not receive a message
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return std::dynamic_pointer_cast<LogicalDiskInfoMessage>(msg);
|
||||||
|
}
|
||||||
|
|
||||||
int Communication::addMessageCallback(const MessageCallback& cb) {
|
int Communication::addMessageCallback(const MessageCallback& cb) {
|
||||||
std::lock_guard<std::mutex> lk(messageCallbacksLock);
|
std::lock_guard<std::mutex> lk(messageCallbacksLock);
|
||||||
messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb));
|
messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb));
|
||||||
|
|
@ -180,7 +210,8 @@ bool Communication::removeMessageCallback(int id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Message> Communication::waitForMessageSync(std::function<bool(void)> onceWaitingDo, MessageFilter f, std::chrono::milliseconds timeout) {
|
std::shared_ptr<Message> Communication::waitForMessageSync(std::function<bool(void)> onceWaitingDo,
|
||||||
|
const std::shared_ptr<MessageFilter>& f, std::chrono::milliseconds timeout) {
|
||||||
std::mutex m;
|
std::mutex m;
|
||||||
std::condition_variable cv;
|
std::condition_variable cv;
|
||||||
std::shared_ptr<Message> returnedMessage;
|
std::shared_ptr<Message> returnedMessage;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#include "icsneo/communication/message/serialnumbermessage.h"
|
#include "icsneo/communication/message/serialnumbermessage.h"
|
||||||
#include "icsneo/communication/message/resetstatusmessage.h"
|
#include "icsneo/communication/message/resetstatusmessage.h"
|
||||||
#include "icsneo/communication/message/readsettingsmessage.h"
|
#include "icsneo/communication/message/readsettingsmessage.h"
|
||||||
|
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||||
|
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||||
#include "icsneo/communication/command.h"
|
#include "icsneo/communication/command.h"
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
|
|
@ -11,6 +13,8 @@
|
||||||
#include "icsneo/communication/packet/flexraypacket.h"
|
#include "icsneo/communication/packet/flexraypacket.h"
|
||||||
#include "icsneo/communication/packet/iso9141packet.h"
|
#include "icsneo/communication/packet/iso9141packet.h"
|
||||||
#include "icsneo/communication/packet/versionpacket.h"
|
#include "icsneo/communication/packet/versionpacket.h"
|
||||||
|
#include "icsneo/communication/packet/ethphyregpacket.h"
|
||||||
|
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
@ -24,7 +28,7 @@ uint64_t Decoder::GetUInt64FromLEBytes(const uint8_t* bytes) {
|
||||||
|
|
||||||
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
|
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
|
||||||
switch(packet->network.getType()) {
|
switch(packet->network.getType()) {
|
||||||
case Network::Type::Ethernet:
|
case Network::Type::Ethernet: {
|
||||||
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
|
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
|
||||||
if(!result) {
|
if(!result) {
|
||||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
|
|
@ -33,9 +37,11 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
|
|
||||||
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
||||||
// The resolution depends on the device
|
// The resolution depends on the device
|
||||||
result->timestamp *= timestampResolution;
|
EthernetMessage& eth = *static_cast<EthernetMessage*>(result.get());
|
||||||
result->network = packet->network;
|
eth.timestamp *= timestampResolution;
|
||||||
|
eth.network = packet->network;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
case Network::Type::CAN:
|
case Network::Type::CAN:
|
||||||
case Network::Type::SWCAN:
|
case Network::Type::SWCAN:
|
||||||
case Network::Type::LSFTCAN: {
|
case Network::Type::LSFTCAN: {
|
||||||
|
|
@ -49,10 +55,28 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
return false; // A nullptr was returned, the packet was malformed
|
return false; // A nullptr was returned, the packet was malformed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
||||||
// The resolution depends on the device
|
// The resolution depends on the device
|
||||||
result->timestamp *= timestampResolution;
|
result->timestamp *= timestampResolution;
|
||||||
result->network = packet->network;
|
|
||||||
|
switch(result->type) {
|
||||||
|
case Message::Type::Frame: {
|
||||||
|
CANMessage& can = *static_cast<CANMessage*>(result.get());
|
||||||
|
can.network = packet->network;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Message::Type::CANErrorCount: {
|
||||||
|
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get());
|
||||||
|
can.network = packet->network;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
|
return false; // An unknown type was returned, the packet was malformed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Network::Type::FlexRay: {
|
case Network::Type::FlexRay: {
|
||||||
|
|
@ -66,10 +90,12 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
return false; // A nullptr was returned, the packet was malformed
|
return false; // A nullptr was returned, the packet was malformed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
||||||
// The resolution depends on the device
|
// The resolution depends on the device
|
||||||
result->timestamp *= timestampResolution;
|
FlexRayMessage& fr = *static_cast<FlexRayMessage*>(result.get());
|
||||||
result->network = packet->network;
|
fr.timestamp *= timestampResolution;
|
||||||
|
fr.network = packet->network;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Network::Type::ISO9141: {
|
case Network::Type::ISO9141: {
|
||||||
|
|
@ -84,25 +110,24 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
|
|
||||||
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
||||||
// The resolution depends on the device
|
// The resolution depends on the device
|
||||||
result->timestamp *= timestampResolution;
|
ISO9141Message& iso = *static_cast<ISO9141Message*>(result.get());
|
||||||
result->network = packet->network;
|
iso.timestamp *= timestampResolution;
|
||||||
|
iso.network = packet->network;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Network::Type::Internal: {
|
case Network::Type::Internal: {
|
||||||
switch(packet->network.getNetID()) {
|
switch(packet->network.getNetID()) {
|
||||||
case Network::NetID::Reset_Status: {
|
case Network::NetID::Reset_Status: {
|
||||||
if(packet->data.size() < sizeof(HardwareResetStatusPacket)) {
|
// We can deal with not having the last two fields (voltage and temperature)
|
||||||
|
if(packet->data.size() < (sizeof(HardwareResetStatusPacket) - (sizeof(uint16_t) * 2))) {
|
||||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
|
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
|
||||||
auto msg = std::make_shared<ResetStatusMessage>();
|
auto msg = std::make_shared<ResetStatusMessage>();
|
||||||
msg->network = packet->network;
|
|
||||||
msg->mainLoopTime = data->main_loop_time_25ns * 25;
|
msg->mainLoopTime = data->main_loop_time_25ns * 25;
|
||||||
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
|
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
|
||||||
msg->busVoltage = data->busVoltage;
|
|
||||||
msg->deviceTemperature = data->deviceTemperature;
|
|
||||||
msg->justReset = data->status.just_reset;
|
msg->justReset = data->status.just_reset;
|
||||||
msg->comEnabled = data->status.com_enabled;
|
msg->comEnabled = data->status.com_enabled;
|
||||||
msg->cmRunning = data->status.cm_is_running;
|
msg->cmRunning = data->status.cm_is_running;
|
||||||
|
|
@ -116,6 +141,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
msg->cmTooBig = data->status.cm_too_big;
|
msg->cmTooBig = data->status.cm_too_big;
|
||||||
msg->hidUsbState = data->status.hidUsbState;
|
msg->hidUsbState = data->status.hidUsbState;
|
||||||
msg->fpgaUsbState = data->status.fpgaUsbState;
|
msg->fpgaUsbState = data->status.fpgaUsbState;
|
||||||
|
if(packet->data.size() >= sizeof(HardwareResetStatusPacket)) {
|
||||||
|
msg->busVoltage = data->busVoltage;
|
||||||
|
msg->deviceTemperature = data->deviceTemperature;
|
||||||
|
}
|
||||||
result = msg;
|
result = msg;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -124,9 +153,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
// They come in as CAN but we will handle them in the device rather than
|
// They come in as CAN but we will handle them in the device rather than
|
||||||
// passing them onto the user.
|
// passing them onto the user.
|
||||||
if(packet->data.size() < 24) {
|
if(packet->data.size() < 24) {
|
||||||
result = std::make_shared<Message>();
|
auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device);
|
||||||
result->network = packet->network;
|
result = rawmsg;
|
||||||
result->data = packet->data;
|
rawmsg->data = packet->data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,17 +164,33 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
return false; // A nullptr was returned, the packet was malformed
|
return false; // A nullptr was returned, the packet was malformed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
|
||||||
// The resolution depends on the device
|
// The resolution depends on the device
|
||||||
result->timestamp *= timestampResolution;
|
auto* raw = dynamic_cast<RawMessage*>(result.get());
|
||||||
result->network = packet->network;
|
if(raw == nullptr) {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
|
return false; // A nullptr was returned, the packet was malformed
|
||||||
|
}
|
||||||
|
raw->timestamp *= timestampResolution;
|
||||||
|
raw->network = packet->network;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Network::NetID::DeviceStatus: {
|
case Network::NetID::DeviceStatus: {
|
||||||
result = std::make_shared<Message>();
|
|
||||||
result->network = packet->network;
|
|
||||||
// Just pass along the data, the device needs to handle this itself
|
// Just pass along the data, the device needs to handle this itself
|
||||||
result->data = packet->data;
|
result = std::make_shared<RawMessage>(packet->network, packet->data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Network::NetID::NeoMemorySDRead: {
|
||||||
|
if(packet->data.size() != 512 + sizeof(uint32_t)) {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
|
return false; // Should get enough data for a start address and sector
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto msg = std::make_shared<NeoReadMemorySDMessage>();
|
||||||
|
result = msg;
|
||||||
|
msg->startAddress = *reinterpret_cast<uint32_t*>(packet->data.data());
|
||||||
|
msg->data.insert(msg->data.end(), packet->data.begin() + 4, packet->data.end());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Network::NetID::FlexRayControl: {
|
case Network::NetID::FlexRayControl: {
|
||||||
|
|
@ -161,7 +206,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
switch((Command)packet->data[0]) {
|
switch((Command)packet->data[0]) {
|
||||||
case Command::RequestSerialNumber: {
|
case Command::RequestSerialNumber: {
|
||||||
auto msg = std::make_shared<SerialNumberMessage>();
|
auto msg = std::make_shared<SerialNumberMessage>();
|
||||||
msg->network = packet->network;
|
|
||||||
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
|
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
|
||||||
// The device sends 64-bits of serial number, but we never use more than 32-bits.
|
// The device sends 64-bits of serial number, but we never use more than 32-bits.
|
||||||
msg->deviceSerial = Device::SerialNumToString((uint32_t)serial);
|
msg->deviceSerial = Device::SerialNumToString((uint32_t)serial);
|
||||||
|
|
@ -194,7 +238,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
auto msg = std::make_shared<Main51Message>();
|
auto msg = std::make_shared<Main51Message>();
|
||||||
msg->network = packet->network;
|
|
||||||
msg->command = Command(packet->data[0]);
|
msg->command = Command(packet->data[0]);
|
||||||
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
|
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
|
||||||
result = msg;
|
result = msg;
|
||||||
|
|
@ -218,7 +261,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
}
|
}
|
||||||
case Network::NetID::ReadSettings: {
|
case Network::NetID::ReadSettings: {
|
||||||
auto msg = std::make_shared<ReadSettingsMessage>();
|
auto msg = std::make_shared<ReadSettingsMessage>();
|
||||||
msg->network = packet->network;
|
|
||||||
msg->response = ReadSettingsMessage::Response(packet->data[0]);
|
msg->response = ReadSettingsMessage::Response(packet->data[0]);
|
||||||
|
|
||||||
if(msg->response == ReadSettingsMessage::Response::OK) {
|
if(msg->response == ReadSettingsMessage::Response::OK) {
|
||||||
|
|
@ -236,6 +278,22 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
result = msg;
|
result = msg;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
case Network::NetID::LogicalDiskInfo: {
|
||||||
|
result = LogicalDiskInfoPacket::DecodeToMessage(packet->data);
|
||||||
|
if(!result) {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case Network::NetID::EthPHYControl: {
|
||||||
|
result = HardwareEthernetPhyRegisterPacket::DecodeToMessage(packet->data, report);
|
||||||
|
if(!result) {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -243,9 +301,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the moment other types of messages will automatically be decoded as raw messages
|
// For the moment other types of messages will automatically be decoded as raw messages
|
||||||
auto msg = std::make_shared<Message>();
|
result = std::make_shared<RawMessage>(packet->network, packet->data);
|
||||||
msg->network = packet->network;
|
|
||||||
msg->data = packet->data;
|
|
||||||
result = msg;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
#include "icsneo/communication/driver.h"
|
#include "icsneo/communication/driver.h"
|
||||||
|
|
||||||
|
//#define ICSNEO_DRIVER_DEBUG_PRINTS
|
||||||
|
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
bool Driver::read(std::vector<uint8_t>& bytes, size_t limit) {
|
bool Driver::read(std::vector<uint8_t>& bytes, size_t limit) {
|
||||||
|
|
@ -35,6 +41,18 @@ bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds tim
|
||||||
|
|
||||||
bytes.resize(actuallyRead);
|
bytes.resize(actuallyRead);
|
||||||
|
|
||||||
|
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
|
||||||
|
if(actuallyRead > 0) {
|
||||||
|
std::cout << "Read data: (" << actuallyRead << ')' << std::hex << std::endl;
|
||||||
|
for(int i = 0; i < actuallyRead; i += 16) {
|
||||||
|
for(int j = 0; j < std::min<int>(actuallyRead - i, 16); j++)
|
||||||
|
std::cout << std::setw(2) << std::setfill('0') << uint32_t(bytes[i+j]) << ' ';
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return actuallyRead > 0;
|
return actuallyRead > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,17 +63,18 @@ bool Driver::write(const std::vector<uint8_t>& bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(writeBlocks) {
|
if(writeBlocks) {
|
||||||
if(writeQueue.size_approx() > writeQueueSize)
|
if(writeQueueFull()) {
|
||||||
while(writeQueue.size_approx() > (writeQueueSize * 3 / 4))
|
while(writeQueueAlmostFull()) // Wait until we have some decent amount of space
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(writeQueue.size_approx() > writeQueueSize) {
|
if(writeQueueFull()) {
|
||||||
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
|
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = writeQueue.enqueue(WriteOperation(bytes));
|
const bool ret = writeInternal(bytes);
|
||||||
if(!ret)
|
if(!ret)
|
||||||
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
|
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,124 +4,167 @@
|
||||||
#include "icsneo/communication/packet/ethernetpacket.h"
|
#include "icsneo/communication/packet/ethernetpacket.h"
|
||||||
#include "icsneo/communication/packet/iso9141packet.h"
|
#include "icsneo/communication/packet/iso9141packet.h"
|
||||||
#include "icsneo/communication/packet/canpacket.h"
|
#include "icsneo/communication/packet/canpacket.h"
|
||||||
|
#include "icsneo/communication/packet/ethphyregpacket.h"
|
||||||
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
|
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
|
||||||
bool shortFormat = false;
|
bool shortFormat = false;
|
||||||
bool useResultAsBuffer = false; // Otherwise it's expected that we use message->data
|
std::vector<uint8_t>* buffer = &result;
|
||||||
|
uint16_t netid = 0;
|
||||||
result.clear();
|
result.clear();
|
||||||
|
|
||||||
switch(message->network.getType()) {
|
switch(message->type) {
|
||||||
case Network::Type::Ethernet: {
|
case Message::Type::Frame: {
|
||||||
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
|
auto frame = std::dynamic_pointer_cast<Frame>(message);
|
||||||
if(!ethmsg) {
|
|
||||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
|
||||||
return false; // The message was not a properly formed EthernetMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
useResultAsBuffer = true;
|
// Frame uses frame->data as the buffer unless directed otherwise
|
||||||
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
|
buffer = &frame->data;
|
||||||
return false;
|
netid = uint16_t(frame->network.getNetID());
|
||||||
|
|
||||||
|
switch(frame->network.getType()) {
|
||||||
|
case Network::Type::Ethernet: {
|
||||||
|
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
|
||||||
|
if(!ethmsg) {
|
||||||
|
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||||
|
return false; // The message was not a properly formed EthernetMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = &result;
|
||||||
|
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} // End of Network::Type::Ethernet
|
||||||
|
case Network::Type::CAN:
|
||||||
|
case Network::Type::SWCAN:
|
||||||
|
case Network::Type::LSFTCAN: {
|
||||||
|
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
|
||||||
|
if(!canmsg) {
|
||||||
|
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||||
|
return false; // The message was not a properly formed CANMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!supportCANFD && canmsg->isCANFD) {
|
||||||
|
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
|
||||||
|
return false; // This device does not support CAN FD
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = &result;
|
||||||
|
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
|
||||||
|
return false; // The CANMessage was malformed
|
||||||
|
|
||||||
|
break;
|
||||||
|
} // End of Network::Type::CAN
|
||||||
|
case Network::Type::ISO9141: {
|
||||||
|
auto isomsg = std::dynamic_pointer_cast<ISO9141Message>(message);
|
||||||
|
if(!isomsg) {
|
||||||
|
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||||
|
return false; // The message was not a properly formed ISO9141Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the normal message wrapping at the bottom since we need to send multiple
|
||||||
|
// packets to the device. This function just encodes them back to back into `result`
|
||||||
|
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
|
||||||
|
} // End of Network::Type::ISO9141
|
||||||
|
default:
|
||||||
|
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
} // End of Network::Type::Ethernet
|
}
|
||||||
case Network::Type::CAN:
|
case Message::Type::RawMessage: {
|
||||||
case Network::Type::SWCAN:
|
auto raw = std::dynamic_pointer_cast<RawMessage>(message);
|
||||||
case Network::Type::LSFTCAN: {
|
|
||||||
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
|
|
||||||
if(!canmsg) {
|
|
||||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
|
||||||
return false; // The message was not a properly formed CANMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!supportCANFD && canmsg->isCANFD) {
|
// Raw message uses raw->data as the buffer unless directed otherwise
|
||||||
report(APIEvent::Type::CANFDNotSupported, APIEvent::Severity::Error);
|
buffer = &raw->data;
|
||||||
return false; // This device does not support CAN FD
|
netid = uint16_t(raw->network.getNetID());
|
||||||
}
|
|
||||||
|
|
||||||
useResultAsBuffer = true;
|
switch(raw->network.getNetID()) {
|
||||||
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
|
|
||||||
return false; // The CANMessage was malformed
|
|
||||||
|
|
||||||
break;
|
|
||||||
} // End of Network::Type::CAN
|
|
||||||
case Network::Type::ISO9141: {
|
|
||||||
auto isomsg = std::dynamic_pointer_cast<ISO9141Message>(message);
|
|
||||||
if(!isomsg) {
|
|
||||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
|
||||||
return false; // The message was not a properly formed ISO9141Message
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip the normal message wrapping at the bottom since we need to send multiple
|
|
||||||
// packets to the device. This function just encodes them back to back into `result`
|
|
||||||
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
|
|
||||||
} // End of Network::Type::ISO9141
|
|
||||||
default:
|
|
||||||
switch(message->network.getNetID()) {
|
|
||||||
case Network::NetID::Device:
|
case Network::NetID::Device:
|
||||||
shortFormat = true;
|
shortFormat = true;
|
||||||
break;
|
break;
|
||||||
case Network::NetID::Main51: {
|
|
||||||
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
|
|
||||||
if(!m51msg) {
|
|
||||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
|
||||||
return false; // The message was not a properly formed Main51Message
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!m51msg->forceShortFormat) {
|
|
||||||
// Main51 can be sent as a long message without setting the NetID to RED first
|
|
||||||
// Size in long format is the size of the entire packet
|
|
||||||
// So +1 for AA header, +1 for short format header, and +2 for long format size
|
|
||||||
uint16_t size = uint16_t(message->data.size()) + 1 + 1 + 2;
|
|
||||||
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
|
|
||||||
size += 1; // Main51 Command
|
|
||||||
message->data.insert(message->data.begin(), {
|
|
||||||
(uint8_t)Network::NetID::Main51, // 0x0B for long message
|
|
||||||
(uint8_t)size, // Size, little endian 16-bit
|
|
||||||
(uint8_t)(size >> 8),
|
|
||||||
(uint8_t)m51msg->command
|
|
||||||
});
|
|
||||||
result = packetizer.packetWrap(message->data, shortFormat);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
message->data.insert(message->data.begin(), { uint8_t(m51msg->command) });
|
|
||||||
shortFormat = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Network::NetID::RED_OLDFORMAT: {
|
case Network::NetID::RED_OLDFORMAT: {
|
||||||
// See the decoder for an explanation
|
// See the decoder for an explanation
|
||||||
// We expect the network byte to be populated already in data, but not the length
|
// We expect the network byte to be populated already in data, but not the length
|
||||||
uint16_t length = uint16_t(message->data.size()) - 1;
|
uint16_t length = uint16_t(raw->data.size()) - 1;
|
||||||
message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
|
raw->data.insert(raw->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Message::Type::Main51: {
|
||||||
|
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
|
||||||
|
if(!m51msg) {
|
||||||
|
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||||
|
return false; // The message was not a properly formed Main51Message
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = &m51msg->data;
|
||||||
|
netid = uint16_t(Network::NetID::Main51);
|
||||||
|
|
||||||
|
if(!m51msg->forceShortFormat) {
|
||||||
|
// Main51 can be sent as a long message without setting the NetID to RED first
|
||||||
|
// Size in long format is the size of the entire packet
|
||||||
|
// So +1 for AA header, +1 for short format header, and +2 for long format size
|
||||||
|
uint16_t size = uint16_t(m51msg->data.size()) + 1 + 1 + 2;
|
||||||
|
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
|
||||||
|
size += 1; // Main51 Command
|
||||||
|
m51msg->data.insert(m51msg->data.begin(), {
|
||||||
|
(uint8_t)Network::NetID::Main51, // 0x0B for long message
|
||||||
|
(uint8_t)size, // Size, little endian 16-bit
|
||||||
|
(uint8_t)(size >> 8),
|
||||||
|
(uint8_t)m51msg->command
|
||||||
|
});
|
||||||
|
result = packetizer.packetWrap(m51msg->data, shortFormat);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m51msg->data.insert(m51msg->data.begin(), { uint8_t(m51msg->command) });
|
||||||
|
shortFormat = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Message::Type::EthernetPhyRegister: {
|
||||||
|
if(!supportEthPhy) {
|
||||||
|
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto ethPhyMessage = std::dynamic_pointer_cast<EthPhyMessage>(message);
|
||||||
|
if(!ethPhyMessage) {
|
||||||
|
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!HardwareEthernetPhyRegisterPacket::EncodeFromMessage(*ethPhyMessage, result, report))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Early returns may mean we don't reach this far, check the type you're concerned with
|
// Early returns may mean we don't reach this far, check the type you're concerned with
|
||||||
auto& buffer = useResultAsBuffer ? result : message->data;
|
|
||||||
|
|
||||||
if(shortFormat) {
|
if(shortFormat) {
|
||||||
buffer.insert(buffer.begin(), (uint8_t(buffer.size()) << 4) | uint8_t(message->network.getNetID()));
|
buffer->insert(buffer->begin(), (uint8_t(buffer->size()) << 4) | uint8_t(netid));
|
||||||
} else {
|
} else {
|
||||||
// Size in long format is the size of the entire packet
|
// Size for the host-to-device long format is the size of the entire packet + 1
|
||||||
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
|
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
|
||||||
uint16_t size = uint16_t(buffer.size()) + 1 + 1 + 2 + 2;
|
// Then an extra +1, due to a firmware idiosyncrasy
|
||||||
buffer.insert(buffer.begin(), {
|
uint16_t size = uint16_t(buffer->size()) + 1 + 1 + 2 + 2 + 1;
|
||||||
|
buffer->insert(buffer->begin(), {
|
||||||
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
||||||
(uint8_t)size, // Size, little endian 16-bit
|
(uint8_t)size, // Size, little endian 16-bit
|
||||||
(uint8_t)(size >> 8),
|
(uint8_t)(size >> 8),
|
||||||
(uint8_t)message->network.getNetID(), // NetID, little endian 16-bit
|
(uint8_t)netid, // NetID, little endian 16-bit
|
||||||
(uint8_t)(uint16_t(message->network.getNetID()) >> 8)
|
(uint8_t)(netid >> 8)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
result = packetizer.packetWrap(buffer, shortFormat);
|
result = packetizer.packetWrap(*buffer, shortFormat);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,20 +176,19 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||||
* In this case, command 0x06 is SetLEDState.
|
* In this case, command 0x06 is SetLEDState.
|
||||||
* This old command type is not really used anywhere else.
|
* This old command type is not really used anywhere else.
|
||||||
*/
|
*/
|
||||||
msg = std::make_shared<Message>();
|
auto canmsg = std::make_shared<RawMessage>(Network::NetID::Device);
|
||||||
|
msg = canmsg;
|
||||||
if(arguments.empty()) {
|
if(arguments.empty()) {
|
||||||
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
msg->network = Network::NetID::Device;
|
canmsg->data.reserve(3);
|
||||||
msg->data.reserve(3);
|
canmsg->data.push_back(0x00);
|
||||||
msg->data.push_back(0x00);
|
canmsg->data.push_back(0x06); // SetLEDState
|
||||||
msg->data.push_back(0x06); // SetLEDState
|
canmsg->data.push_back(arguments.at(0)); // See Device::LEDState
|
||||||
msg->data.push_back(arguments.at(0)); // See Device::LEDState
|
|
||||||
} else {
|
} else {
|
||||||
auto m51msg = std::make_shared<Main51Message>();
|
auto m51msg = std::make_shared<Main51Message>();
|
||||||
msg = m51msg;
|
msg = m51msg;
|
||||||
msg->network = Network::NetID::Main51;
|
|
||||||
m51msg->command = cmd;
|
m51msg->command = cmd;
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case Command::ReadSettings:
|
case Command::ReadSettings:
|
||||||
|
|
@ -155,13 +197,14 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
|
||||||
case Command::EnableNetworkCommunicationEx:
|
case Command::EnableNetworkCommunicationEx:
|
||||||
case Command::GetMainVersion:
|
case Command::GetMainVersion:
|
||||||
case Command::GetSecondaryVersions:
|
case Command::GetSecondaryVersions:
|
||||||
|
case Command::NeoReadMemory:
|
||||||
// There is a firmware handling idiosyncrasy with these commands
|
// There is a firmware handling idiosyncrasy with these commands
|
||||||
// They must be encoded in the short format
|
// They must be encoded in the short format
|
||||||
m51msg->forceShortFormat = true;
|
m51msg->forceShortFormat = true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
|
m51msg->data.insert(m51msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return encode(packetizer, result, msg);
|
return encode(packetizer, result, msg);
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,62 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
#define MAX_PACKET_LEN (1490) // MTU - overhead
|
const size_t EthernetPacketizer::MaxPacketLength = 1490; // MTU - overhead
|
||||||
|
|
||||||
static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
|
||||||
void EthernetPacketizer::inputDown(std::vector<uint8_t> bytes) {
|
EthernetPacketizer::EthernetPacket& EthernetPacketizer::newSendPacket(bool first) {
|
||||||
EthernetPacket sendPacket;
|
processedDownPackets.emplace_back();
|
||||||
std::copy(std::begin(hostMAC), std::end(hostMAC), std::begin(sendPacket.srcMAC));
|
EthernetPacket& ret = processedDownPackets.back();
|
||||||
std::copy(std::begin(deviceMAC), std::end(deviceMAC), std::begin(sendPacket.destMAC));
|
if(first) {
|
||||||
|
ret.packetNumber = sequenceDown++;
|
||||||
|
} else {
|
||||||
|
ret.firstPiece = false;
|
||||||
|
if(processedDownPackets.size() > 1)
|
||||||
|
ret.packetNumber = (processedDownPackets.rbegin() + 1)->packetNumber;
|
||||||
|
else
|
||||||
|
assert(false); // This should never be called with !first if there are no packets in the queue
|
||||||
|
}
|
||||||
|
std::copy(std::begin(hostMAC), std::end(hostMAC), std::begin(ret.srcMAC));
|
||||||
|
std::copy(std::begin(deviceMAC), std::end(deviceMAC), std::begin(ret.destMAC));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
sendPacket.packetNumber = sequenceDown++;
|
void EthernetPacketizer::inputDown(std::vector<uint8_t> bytes, bool first) {
|
||||||
sendPacket.payload = std::move(bytes);
|
EthernetPacket* sendPacket = nullptr;
|
||||||
|
if(first && !processedDownPackets.empty()) {
|
||||||
|
// We have some packets already, let's see if we can add this to the last one
|
||||||
|
if(processedDownPackets.back().payload.size() + bytes.size() <= MaxPacketLength)
|
||||||
|
sendPacket = &processedDownPackets.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sendPacket == nullptr)
|
||||||
|
sendPacket = &newSendPacket(first);
|
||||||
|
|
||||||
|
if(sendPacket->payload.empty())
|
||||||
|
sendPacket->payload = std::move(bytes);
|
||||||
|
else
|
||||||
|
sendPacket->payload.insert(sendPacket->payload.end(), bytes.begin(), bytes.end());
|
||||||
|
|
||||||
// Split packets larger than MTU
|
// Split packets larger than MTU
|
||||||
std::vector<uint8_t> extraData;
|
std::vector<uint8_t> extraData;
|
||||||
if(sendPacket.payload.size() > MAX_PACKET_LEN) {
|
if(sendPacket->payload.size() > MaxPacketLength) {
|
||||||
extraData.insert(extraData.end(), sendPacket.payload.begin() + MAX_PACKET_LEN, sendPacket.payload.end());
|
extraData.insert(extraData.end(), sendPacket->payload.begin() + MaxPacketLength, sendPacket->payload.end());
|
||||||
sendPacket.payload.resize(MAX_PACKET_LEN);
|
sendPacket->payload.resize(MaxPacketLength);
|
||||||
sendPacket.lastPiece = false;
|
sendPacket->lastPiece = false;
|
||||||
}
|
inputDown(std::move(extraData), false);
|
||||||
|
|
||||||
processedDownPackets.push_back(sendPacket.getBytestream());
|
|
||||||
|
|
||||||
if(!extraData.empty()) {
|
|
||||||
sendPacket.payload = std::move(extraData);
|
|
||||||
sendPacket.firstPiece = false;
|
|
||||||
sendPacket.lastPiece = true;
|
|
||||||
processedDownPackets.push_back(sendPacket.getBytestream());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector< std::vector<uint8_t> > EthernetPacketizer::outputDown() {
|
std::vector< std::vector<uint8_t> > EthernetPacketizer::outputDown() {
|
||||||
std::vector< std::vector<uint8_t> > ret = std::move(processedDownPackets);
|
std::vector< std::vector<uint8_t> > ret;
|
||||||
|
ret.reserve(processedDownPackets.size());
|
||||||
|
for(auto&& packet : std::move(processedDownPackets))
|
||||||
|
ret.push_back(packet.getBytestream());
|
||||||
processedDownPackets.clear();
|
processedDownPackets.clear();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -54,7 +75,7 @@ bool EthernetPacketizer::inputUp(std::vector<uint8_t> bytes) {
|
||||||
memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0)
|
memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0)
|
||||||
return false; // Packet is not addressed to us or broadcast
|
return false; // Packet is not addressed to us or broadcast
|
||||||
|
|
||||||
if(memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0)
|
if(!allowInPacketsFromAnyMAC && memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0)
|
||||||
return false; // Not a packet from the device we're concerned with
|
return false; // Not a packet from the device we're concerned with
|
||||||
|
|
||||||
// Handle single packets
|
// Handle single packets
|
||||||
|
|
@ -73,7 +94,7 @@ bool EthernetPacketizer::inputUp(std::vector<uint8_t> bytes) {
|
||||||
|
|
||||||
reassembling = true;
|
reassembling = true;
|
||||||
reassemblingId = packet.packetNumber;
|
reassemblingId = packet.packetNumber;
|
||||||
reassemblingData = std::move(bytes);
|
reassemblingData = std::move(packet.payload);
|
||||||
return !processedUpBytes.empty(); // If there are other packets in the pipe
|
return !processedUpBytes.empty(); // If there are other packets in the pipe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +140,7 @@ int EthernetPacketizer::EthernetPacket::loadBytestream(const std::vector<uint8_t
|
||||||
srcMAC[i] = bytestream[i + 6];
|
srcMAC[i] = bytestream[i + 6];
|
||||||
etherType = (bytestream[12] << 8) | bytestream[13];
|
etherType = (bytestream[12] << 8) | bytestream[13];
|
||||||
icsEthernetHeader = (bytestream[14] << 24) | (bytestream[15] << 16) | (bytestream[16] << 8) | bytestream[17];
|
icsEthernetHeader = (bytestream[14] << 24) | (bytestream[15] << 16) | (bytestream[16] << 8) | bytestream[17];
|
||||||
uint16_t payloadSize = bytestream[18] | (bytestream[19] << 8);
|
payloadSize = bytestream[18] | (bytestream[19] << 8);
|
||||||
packetNumber = bytestream[20] | (bytestream[21] << 8);
|
packetNumber = bytestream[20] | (bytestream[21] << 8);
|
||||||
uint16_t packetInfo = bytestream[22] | (bytestream[23] << 8);
|
uint16_t packetInfo = bytestream[22] | (bytestream[23] << 8);
|
||||||
firstPiece = packetInfo & 1;
|
firstPiece = packetInfo & 1;
|
||||||
|
|
@ -127,17 +148,15 @@ int EthernetPacketizer::EthernetPacket::loadBytestream(const std::vector<uint8_t
|
||||||
bufferHalfFull = (packetInfo >> 2) & 2;
|
bufferHalfFull = (packetInfo >> 2) & 2;
|
||||||
payload = std::vector<uint8_t>(bytestream.begin() + 24, bytestream.end());
|
payload = std::vector<uint8_t>(bytestream.begin() + 24, bytestream.end());
|
||||||
size_t payloadActualSize = payload.size();
|
size_t payloadActualSize = payload.size();
|
||||||
if(payloadActualSize < payloadSize)
|
if(payloadActualSize > payloadSize)
|
||||||
errorWhileDecodingFromBytestream = 1;
|
|
||||||
else
|
|
||||||
payload.resize(payloadSize);
|
payload.resize(payloadSize);
|
||||||
return errorWhileDecodingFromBytestream;
|
return errorWhileDecodingFromBytestream;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
|
std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
|
||||||
size_t payloadSize = payload.size();
|
uint16_t actualPayloadSize = uint16_t(payload.size());
|
||||||
std::vector<uint8_t> bytestream;
|
std::vector<uint8_t> bytestream;
|
||||||
bytestream.reserve(6 + 6 + 2 + 4 + 2 + 2 + 2 + payloadSize);
|
bytestream.reserve(6 + 6 + 2 + 4 + 2 + 2 + 2 + actualPayloadSize);
|
||||||
for(size_t i = 0; i < 6; i++)
|
for(size_t i = 0; i < 6; i++)
|
||||||
bytestream.push_back(destMAC[i]);
|
bytestream.push_back(destMAC[i]);
|
||||||
for(size_t i = 0; i < 6; i++)
|
for(size_t i = 0; i < 6; i++)
|
||||||
|
|
@ -150,9 +169,10 @@ std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
|
||||||
bytestream.push_back((uint8_t)(icsEthernetHeader >> 16));
|
bytestream.push_back((uint8_t)(icsEthernetHeader >> 16));
|
||||||
bytestream.push_back((uint8_t)(icsEthernetHeader >> 8));
|
bytestream.push_back((uint8_t)(icsEthernetHeader >> 8));
|
||||||
bytestream.push_back((uint8_t)(icsEthernetHeader));
|
bytestream.push_back((uint8_t)(icsEthernetHeader));
|
||||||
|
uint16_t declaredPayloadSize = payloadSize ? payloadSize : actualPayloadSize;
|
||||||
// The payload size comes next, it's little endian
|
// The payload size comes next, it's little endian
|
||||||
bytestream.push_back((uint8_t)(payloadSize));
|
bytestream.push_back((uint8_t)(declaredPayloadSize));
|
||||||
bytestream.push_back((uint8_t)(payloadSize >> 8));
|
bytestream.push_back((uint8_t)(declaredPayloadSize >> 8));
|
||||||
// Packet number is little endian
|
// Packet number is little endian
|
||||||
bytestream.push_back((uint8_t)(packetNumber));
|
bytestream.push_back((uint8_t)(packetNumber));
|
||||||
bytestream.push_back((uint8_t)(packetNumber >> 8));
|
bytestream.push_back((uint8_t)(packetNumber >> 8));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
|
|
||||||
|
namespace icsneo
|
||||||
|
{
|
||||||
|
bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t phyAddrOrPort, uint8_t pageOrDevice, uint16_t regAddr, uint16_t regVal, bool enabled)
|
||||||
|
{
|
||||||
|
auto msg = std::make_shared<PhyMessage>();
|
||||||
|
msg->Clause45Enable = clause45;
|
||||||
|
msg->Enabled = enabled;
|
||||||
|
msg->WriteEnable = writeEnable;
|
||||||
|
msg->version = 1u;
|
||||||
|
if( (FiveBits < phyAddrOrPort) ||
|
||||||
|
(clause45 && (FiveBits < pageOrDevice)) ||
|
||||||
|
(!clause45 && (FiveBits < regAddr)) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(clause45)
|
||||||
|
{
|
||||||
|
msg->clause45.port = phyAddrOrPort;
|
||||||
|
msg->clause45.device = pageOrDevice;
|
||||||
|
msg->clause45.regAddr = regAddr;
|
||||||
|
msg->clause45.regVal = regVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg->clause22.phyAddr = phyAddrOrPort;
|
||||||
|
msg->clause22.page = pageOrDevice;
|
||||||
|
msg->clause22.regAddr = regAddr;
|
||||||
|
msg->clause22.regVal = regVal;
|
||||||
|
}
|
||||||
|
return appendPhyMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message)
|
||||||
|
{
|
||||||
|
if(message != nullptr)
|
||||||
|
{
|
||||||
|
messages.push_back(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EthPhyMessage::getMessageCount() const
|
||||||
|
{
|
||||||
|
return messages.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -64,9 +64,7 @@ std::vector<uint8_t> FlexRayControlMessage::BuildWriteMessageBufferArgs(
|
||||||
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
|
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() {
|
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message(Message::Type::FlexRayControl) {
|
||||||
network = Network::NetID::FlexRayControl;
|
|
||||||
|
|
||||||
if(packet.data.size() < 2)
|
if(packet.data.size() < 2)
|
||||||
return; // huh?
|
return; // huh?
|
||||||
controller = packet.data[0];
|
controller = packet.data[0];
|
||||||
|
|
|
||||||
|
|
@ -1,87 +1,116 @@
|
||||||
#include "icsneo/communication/message/neomessage.h"
|
#include "icsneo/communication/message/neomessage.h"
|
||||||
#include "icsneo/communication/message/canmessage.h"
|
#include "icsneo/communication/message/canmessage.h"
|
||||||
#include "icsneo/communication/message/ethernetmessage.h"
|
#include "icsneo/communication/message/ethernetmessage.h"
|
||||||
|
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
|
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
|
||||||
// This function is not responsible for storing the message!
|
// This function is not responsible for storing the message!
|
||||||
// Keep the shared_ptr around for the lifetime of the data access
|
// Keep the shared_ptr around for the lifetime of the data access
|
||||||
const auto type = message->network.getType();
|
|
||||||
neomessage_t neomsg = {}; // Clear out the memory
|
neomessage_t neomsg = {}; // Clear out the memory
|
||||||
neomsg.netid = (uint32_t)message->network.getNetID();
|
neomsg.messageType = (neomessagetype_t)message->type;
|
||||||
neomsg.type = (uint8_t)type;
|
|
||||||
neomsg.description = message->description;
|
|
||||||
neomsg.length = message->data.size();
|
|
||||||
neomsg.data = message->data.data();
|
|
||||||
neomsg.timestamp = message->timestamp;
|
neomsg.timestamp = message->timestamp;
|
||||||
neomsg.status.globalError = message->error;
|
switch (message->type)
|
||||||
neomsg.status.transmitMessage = message->transmitted;
|
{
|
||||||
|
case Message::Type::Frame: {
|
||||||
|
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
|
||||||
|
auto framemsg = std::static_pointer_cast<Frame>(message);
|
||||||
|
const auto netType = framemsg->network.getType();
|
||||||
|
frame.netid = (neonetid_t)framemsg->network.getNetID();
|
||||||
|
frame.type = (neonettype_t)netType;
|
||||||
|
frame.description = framemsg->description;
|
||||||
|
frame.length = framemsg->data.size();
|
||||||
|
frame.data = framemsg->data.data();
|
||||||
|
frame.timestamp = framemsg->timestamp;
|
||||||
|
frame.status.globalError = framemsg->error;
|
||||||
|
frame.status.transmitMessage = framemsg->transmitted;
|
||||||
|
|
||||||
switch(type) {
|
switch(netType) {
|
||||||
case Network::Type::CAN:
|
case Network::Type::CAN:
|
||||||
case Network::Type::SWCAN:
|
case Network::Type::SWCAN:
|
||||||
case Network::Type::LSFTCAN: {
|
case Network::Type::LSFTCAN: {
|
||||||
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
|
neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
|
||||||
auto canmsg = std::static_pointer_cast<CANMessage>(message);
|
auto canmsg = std::static_pointer_cast<CANMessage>(message);
|
||||||
can.arbid = canmsg->arbid;
|
can.arbid = canmsg->arbid;
|
||||||
can.dlcOnWire = canmsg->dlcOnWire;
|
can.dlcOnWire = canmsg->dlcOnWire;
|
||||||
can.status.extendedFrame = canmsg->isExtended;
|
can.status.extendedFrame = canmsg->isExtended;
|
||||||
can.status.remoteFrame = canmsg->isRemote;
|
can.status.remoteFrame = canmsg->isRemote;
|
||||||
can.status.canfdRTR = canmsg->isRemote;
|
can.status.canfdRTR = canmsg->isRemote;
|
||||||
can.status.canfdFDF = canmsg->isCANFD;
|
can.status.canfdFDF = canmsg->isCANFD;
|
||||||
can.status.canfdBRS = canmsg->baudrateSwitch;
|
can.status.canfdBRS = canmsg->baudrateSwitch;
|
||||||
can.status.canfdESI = canmsg->errorStateIndicator;
|
can.status.canfdESI = canmsg->errorStateIndicator;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case Network::Type::Ethernet: {
|
||||||
|
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
|
||||||
|
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
|
||||||
|
eth.preemptionFlags = ethmsg->preemptionFlags;
|
||||||
|
eth.status.incompleteFrame = ethmsg->frameTooShort;
|
||||||
|
// TODO Fill in extra status bits
|
||||||
|
//eth.status.xyz = ethmsg->preemptionEnabled;
|
||||||
|
//eth.status.xyz = ethmsg->fcsAvailable;
|
||||||
|
//eth.status.xyz = ethmsg->noPadding;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// TODO Implement others
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Network::Type::Ethernet: {
|
break;
|
||||||
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
|
}
|
||||||
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
|
case Message::Type::CANErrorCount: {
|
||||||
eth.preemptionFlags = ethmsg->preemptionFlags;
|
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
|
||||||
eth.status.incompleteFrame = ethmsg->frameTooShort;
|
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message);
|
||||||
// TODO Fill in extra status bits
|
canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
|
||||||
//eth.status.xyz = ethmsg->preemptionEnabled;
|
canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
|
||||||
//eth.status.xyz = ethmsg->fcsAvailable;
|
canerror.status.canBusOff = canerrormsg->busOff;
|
||||||
//eth.status.xyz = ethmsg->noPadding;
|
canerror.netid = (neonetid_t)canerrormsg->network.getNetID();
|
||||||
break;
|
canerror.type = (neonettype_t)canerrormsg->network.getType();
|
||||||
}
|
break;
|
||||||
default:
|
}
|
||||||
// TODO Implement others
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return neomsg;
|
return neomsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
|
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
|
||||||
const Network network = neomessage->netid;
|
switch((Message::Type)neomessage->messageType) {
|
||||||
switch(network.getType()) {
|
case Message::Type::Frame: {
|
||||||
case Network::Type::CAN:
|
const Network network = ((neomessage_frame_t*)neomessage)->netid;
|
||||||
case Network::Type::SWCAN:
|
switch(network.getType()) {
|
||||||
case Network::Type::LSFTCAN: {
|
case Network::Type::CAN:
|
||||||
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
|
case Network::Type::SWCAN:
|
||||||
auto canmsg = std::make_shared<CANMessage>();
|
case Network::Type::LSFTCAN: {
|
||||||
canmsg->network = network;
|
neomessage_can_t& can = *(neomessage_can_t*)neomessage;
|
||||||
canmsg->description = can.description;
|
auto canmsg = std::make_shared<CANMessage>();
|
||||||
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
|
canmsg->network = network;
|
||||||
canmsg->arbid = can.arbid;
|
canmsg->description = can.description;
|
||||||
canmsg->isExtended = can.status.extendedFrame;
|
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
|
||||||
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
|
canmsg->arbid = can.arbid;
|
||||||
canmsg->isCANFD = can.status.canfdFDF;
|
canmsg->dlcOnWire = can.dlcOnWire;
|
||||||
canmsg->baudrateSwitch = can.status.canfdBRS;
|
canmsg->isExtended = can.status.extendedFrame;
|
||||||
canmsg->errorStateIndicator = can.status.canfdESI;
|
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
|
||||||
return canmsg;
|
canmsg->isCANFD = can.status.canfdFDF;
|
||||||
|
canmsg->baudrateSwitch = can.status.canfdBRS;
|
||||||
|
canmsg->errorStateIndicator = can.status.canfdESI;
|
||||||
|
return canmsg;
|
||||||
|
}
|
||||||
|
case Network::Type::Ethernet: {
|
||||||
|
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
|
||||||
|
auto ethmsg = std::make_shared<EthernetMessage>();
|
||||||
|
ethmsg->network = network;
|
||||||
|
ethmsg->description = eth.description;
|
||||||
|
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
|
||||||
|
return ethmsg;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case Network::Type::Ethernet: {
|
default: break;
|
||||||
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
|
|
||||||
auto ethmsg = std::make_shared<EthernetMessage>();
|
|
||||||
ethmsg->network = network;
|
|
||||||
ethmsg->description = eth.description;
|
|
||||||
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
|
|
||||||
return ethmsg;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// TODO Implement others
|
|
||||||
return std::shared_ptr<Message>();
|
|
||||||
}
|
}
|
||||||
|
return std::shared_ptr<Message>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include "icsneo/communication/command.h"
|
#include "icsneo/communication/command.h"
|
||||||
#include "icsneo/communication/decoder.h"
|
#include "icsneo/communication/decoder.h"
|
||||||
#include "icsneo/communication/packetizer.h"
|
#include "icsneo/communication/packetizer.h"
|
||||||
|
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
|
|
@ -134,6 +135,12 @@ void MultiChannelCommunication::hidReadTask() {
|
||||||
if(numVnets >= 3)
|
if(numVnets >= 3)
|
||||||
currentQueue = &vnetQueues[2];
|
currentQueue = &vnetQueues[2];
|
||||||
break;
|
break;
|
||||||
|
case CommandType::SDCC1_to_HostPC: {
|
||||||
|
auto msg = std::make_shared<NeoReadMemorySDMessage>();
|
||||||
|
std::swap(msg->data, payloadBytes);
|
||||||
|
dispatchMessage(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(currentQueue == nullptr) {
|
if(currentQueue == nullptr) {
|
||||||
|
|
|
||||||
|
|
@ -1,86 +1,129 @@
|
||||||
#include "icsneo/communication/packet/canpacket.h"
|
#include "icsneo/communication/packet/canpacket.h"
|
||||||
|
#include "icsneo/communication/message/canerrorcountmessage.h"
|
||||||
#include "icsneo/platform/optional.h"
|
#include "icsneo/platform/optional.h"
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
static optional<uint8_t> CANFD_DLCToLength(uint8_t length) {
|
static optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
|
||||||
if (length < 8)
|
if (length <= 8)
|
||||||
return length;
|
return length;
|
||||||
|
|
||||||
switch(length) {
|
if (fd) {
|
||||||
case 0x9:
|
switch(length) {
|
||||||
return 12;
|
case 0x9:
|
||||||
case 0xa:
|
return uint8_t(12);
|
||||||
return 16;
|
case 0xa:
|
||||||
case 0xb:
|
return uint8_t(16);
|
||||||
return 20;
|
case 0xb:
|
||||||
case 0xc:
|
return uint8_t(20);
|
||||||
return 24;
|
case 0xc:
|
||||||
case 0xd:
|
return uint8_t(24);
|
||||||
return 32;
|
case 0xd:
|
||||||
case 0xe:
|
return uint8_t(32);
|
||||||
return 48;
|
case 0xe:
|
||||||
case 0xf:
|
return uint8_t(48);
|
||||||
return 64;
|
case 0xf:
|
||||||
}
|
return uint8_t(64);
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
|
||||||
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
|
|
||||||
|
|
||||||
auto msg = std::make_shared<CANMessage>();
|
|
||||||
|
|
||||||
// Arb ID
|
|
||||||
if(data->header.IDE) { // Extended 29-bit ID
|
|
||||||
msg->arbid = (data->header.SID & 0x7ff) << 18;
|
|
||||||
msg->arbid |= (data->eid.EID & 0xfff) << 6;
|
|
||||||
msg->arbid |= (data->dlc.EID2 & 0x3f);
|
|
||||||
msg->isExtended = true;
|
|
||||||
} else { // Standard 11-bit ID
|
|
||||||
msg->arbid = data->header.SID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// DLC
|
|
||||||
uint8_t length = data->dlc.DLC;
|
|
||||||
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
|
|
||||||
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
|
|
||||||
msg->isCANFD = true;
|
|
||||||
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
|
|
||||||
msg->errorStateIndicator = data->header.ESI;
|
|
||||||
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(length);
|
|
||||||
if (lenFromDLC)
|
|
||||||
length = *lenFromDLC;
|
|
||||||
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
|
|
||||||
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
|
|
||||||
// We don't want to overread our buffer, though, so make sure we cap the length
|
|
||||||
length = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data
|
|
||||||
// The first 8 bytes are always in the standard place
|
|
||||||
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
|
|
||||||
msg->data.resize(length); // This data will be all zeros, but the length will be set
|
|
||||||
msg->isRemote = true;
|
|
||||||
} else {
|
|
||||||
msg->data.reserve(length);
|
|
||||||
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
|
|
||||||
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
|
|
||||||
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
|
|
||||||
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
|
|
||||||
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->transmitted = data->eid.TXMSG;
|
return nullopt;
|
||||||
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
|
}
|
||||||
msg->description = data->stats;
|
|
||||||
|
|
||||||
return msg;
|
static optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
|
||||||
|
{
|
||||||
|
if (dataLength <= 8)
|
||||||
|
return uint8_t(dataLength);
|
||||||
|
|
||||||
|
if (fd) {
|
||||||
|
if (dataLength <= 12)
|
||||||
|
return uint8_t(0x9);
|
||||||
|
else if (dataLength <= 16)
|
||||||
|
return uint8_t(0xA);
|
||||||
|
else if (dataLength <= 20)
|
||||||
|
return uint8_t(0xB);
|
||||||
|
else if (dataLength <= 24)
|
||||||
|
return uint8_t(0xC);
|
||||||
|
else if (dataLength <= 32)
|
||||||
|
return uint8_t(0xD);
|
||||||
|
else if (dataLength <= 48)
|
||||||
|
return uint8_t(0xE);
|
||||||
|
else if (dataLength <= 64)
|
||||||
|
return uint8_t(0xF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||||
|
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
|
||||||
|
|
||||||
|
if(data->dlc.RB1) { // Change counts reporting
|
||||||
|
|
||||||
|
const bool busOff = data->data[0] & 0b00100000;
|
||||||
|
|
||||||
|
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
|
||||||
|
} else { // CAN Frame
|
||||||
|
auto msg = std::make_shared<CANMessage>();
|
||||||
|
|
||||||
|
// Arb ID
|
||||||
|
if(data->header.IDE) { // Extended 29-bit ID
|
||||||
|
msg->arbid = (data->header.SID & 0x7ff) << 18;
|
||||||
|
msg->arbid |= (data->eid.EID & 0xfff) << 6;
|
||||||
|
msg->arbid |= (data->dlc.EID2 & 0x3f);
|
||||||
|
msg->isExtended = true;
|
||||||
|
} else { // Standard 11-bit ID
|
||||||
|
msg->arbid = data->header.SID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// DLC
|
||||||
|
uint8_t length = data->dlc.DLC;
|
||||||
|
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
|
||||||
|
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
|
||||||
|
msg->isCANFD = true;
|
||||||
|
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
|
||||||
|
msg->errorStateIndicator = data->header.ESI;
|
||||||
|
const optional<uint8_t> lenFromDLC = CAN_DLCToLength(length, true);
|
||||||
|
if (lenFromDLC)
|
||||||
|
length = *lenFromDLC;
|
||||||
|
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
|
||||||
|
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
|
||||||
|
// We don't want to overread our buffer, though, so make sure we cap the length
|
||||||
|
length = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data
|
||||||
|
// The first 8 bytes are always in the standard place
|
||||||
|
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
|
||||||
|
msg->data.resize(length); // This data will be all zeros, but the length will be set
|
||||||
|
msg->isRemote = true;
|
||||||
|
} else {
|
||||||
|
msg->data.reserve(length);
|
||||||
|
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
|
||||||
|
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
|
||||||
|
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
|
||||||
|
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
|
||||||
|
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->transmitted = data->eid.TXMSG;
|
||||||
|
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
|
||||||
|
msg->description = data->stats;
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
|
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
|
||||||
|
|
@ -90,115 +133,38 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t dataSize = message.data.size();
|
const size_t dataSize = message.data.size();
|
||||||
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD)) {
|
optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, message.isCANFD);
|
||||||
|
if (!dlc.has_value()) {
|
||||||
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
||||||
return false; // Too much data for the protocol
|
return false; // Too much data for the protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message.dlcOnWire > 0xf) {
|
if (message.dlcOnWire != 0) {
|
||||||
// The DLC is only a nibble
|
if(message.dlcOnWire > 0xf) {
|
||||||
// It is actually possible to transmit a standard CAN frame with a DLC > 8
|
// The DLC is only a nibble
|
||||||
// While it is invalid, most controllers will still pass along the received
|
// It is actually possible to transmit a standard CAN frame with a DLC > 8
|
||||||
// frame and 8 bytes of data, so it may be desirable to test behavior with
|
// While it is invalid, most controllers will still pass along the received
|
||||||
// these frames. We let you do it if you set `message.dlcOnWire` for transmit.
|
// frame and 8 bytes of data, so it may be desirable to test behavior with
|
||||||
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
// these frames. We let you do it if you set `message.dlcOnWire` for transmit.
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t lengthNibble = uint8_t(message.data.size());
|
|
||||||
|
|
||||||
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(message.dlcOnWire);
|
|
||||||
if (lenFromDLC.has_value() && *lenFromDLC != 0) {
|
|
||||||
if (*lenFromDLC < lengthNibble) {
|
|
||||||
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*lenFromDLC > lengthNibble)
|
if (message.dlcOnWire < *dlc) {
|
||||||
lengthNibble = *lenFromDLC;
|
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.dlcOnWire > *dlc)
|
||||||
|
dlc = message.dlcOnWire;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t paddingBytes = 0;
|
// The only way this fails is if we're transmitting a DLC > 8 on standard CAN
|
||||||
if(lengthNibble > 8) {
|
const uint8_t paddedLength = CAN_DLCToLength(*dlc, message.isCANFD).value_or(8);
|
||||||
switch(lengthNibble) {
|
const uint8_t paddingBytes = uint8_t(paddedLength - dataSize);
|
||||||
case 9: paddingBytes++;
|
|
||||||
case 10: paddingBytes++;
|
|
||||||
case 11: paddingBytes++;
|
|
||||||
case 12:
|
|
||||||
lengthNibble = 0x9;
|
|
||||||
break;
|
|
||||||
case 13: paddingBytes++;
|
|
||||||
case 14: paddingBytes++;
|
|
||||||
case 15: paddingBytes++;
|
|
||||||
case 16:
|
|
||||||
lengthNibble = 0xA;
|
|
||||||
break;
|
|
||||||
case 17: paddingBytes++;
|
|
||||||
case 18: paddingBytes++;
|
|
||||||
case 19: paddingBytes++;
|
|
||||||
case 20:
|
|
||||||
lengthNibble = 0xB;
|
|
||||||
break;
|
|
||||||
case 21: paddingBytes++;
|
|
||||||
case 22: paddingBytes++;
|
|
||||||
case 23: paddingBytes++;
|
|
||||||
case 24:
|
|
||||||
lengthNibble = 0xC;
|
|
||||||
break;
|
|
||||||
case 25: paddingBytes++;
|
|
||||||
case 26: paddingBytes++;
|
|
||||||
case 27: paddingBytes++;
|
|
||||||
case 28: paddingBytes++;
|
|
||||||
case 29: paddingBytes++;
|
|
||||||
case 30: paddingBytes++;
|
|
||||||
case 31: paddingBytes++;
|
|
||||||
case 32:
|
|
||||||
lengthNibble = 0xD;
|
|
||||||
break;
|
|
||||||
case 33: paddingBytes++;
|
|
||||||
case 34: paddingBytes++;
|
|
||||||
case 35: paddingBytes++;
|
|
||||||
case 36: paddingBytes++;
|
|
||||||
case 37: paddingBytes++;
|
|
||||||
case 38: paddingBytes++;
|
|
||||||
case 39: paddingBytes++;
|
|
||||||
case 40: paddingBytes++;
|
|
||||||
case 41: paddingBytes++;
|
|
||||||
case 42: paddingBytes++;
|
|
||||||
case 43: paddingBytes++;
|
|
||||||
case 44: paddingBytes++;
|
|
||||||
case 45: paddingBytes++;
|
|
||||||
case 46: paddingBytes++;
|
|
||||||
case 47: paddingBytes++;
|
|
||||||
case 48:
|
|
||||||
lengthNibble = 0xE;
|
|
||||||
break;
|
|
||||||
case 49: paddingBytes++;
|
|
||||||
case 50: paddingBytes++;
|
|
||||||
case 51: paddingBytes++;
|
|
||||||
case 52: paddingBytes++;
|
|
||||||
case 53: paddingBytes++;
|
|
||||||
case 54: paddingBytes++;
|
|
||||||
case 55: paddingBytes++;
|
|
||||||
case 56: paddingBytes++;
|
|
||||||
case 57: paddingBytes++;
|
|
||||||
case 58: paddingBytes++;
|
|
||||||
case 59: paddingBytes++;
|
|
||||||
case 60: paddingBytes++;
|
|
||||||
case 61: paddingBytes++;
|
|
||||||
case 62: paddingBytes++;
|
|
||||||
case 63: paddingBytes++;
|
|
||||||
case 64:
|
|
||||||
lengthNibble = 0xF;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
|
||||||
return false; // CAN FD frame may have had an incorrect byte count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-allocate as much memory as we will possibly need for speed
|
// Pre-allocate as much memory as we will possibly need for speed
|
||||||
result.reserve(17 + dataSize + paddingBytes);
|
result.reserve(16 + dataSize + paddingBytes);
|
||||||
|
|
||||||
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
|
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
|
||||||
|
|
||||||
|
|
@ -233,7 +199,7 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
|
||||||
// Status and DLC bits
|
// Status and DLC bits
|
||||||
if(message.isCANFD) {
|
if(message.isCANFD) {
|
||||||
result.push_back(0x0F); // FD Frame
|
result.push_back(0x0F); // FD Frame
|
||||||
uint8_t fdStatusByte = lengthNibble;
|
uint8_t fdStatusByte = *dlc;
|
||||||
if(message.baudrateSwitch)
|
if(message.baudrateSwitch)
|
||||||
fdStatusByte |= 0x80; // BRS status bit
|
fdStatusByte |= 0x80; // BRS status bit
|
||||||
// The firmware does not yet support transmitting ESI
|
// The firmware does not yet support transmitting ESI
|
||||||
|
|
@ -241,13 +207,12 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
|
||||||
} else {
|
} else {
|
||||||
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
|
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
|
||||||
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
|
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
|
||||||
result.push_back((statusNibble << 4) | lengthNibble);
|
result.push_back((statusNibble << 4) | *dlc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now finally the payload
|
// Now finally the payload
|
||||||
result.insert(result.end(), message.data.begin(), message.data.end());
|
result.insert(result.end(), message.data.begin(), message.data.end());
|
||||||
result.resize(result.size() + paddingBytes);
|
result.resize(result.size() + paddingBytes);
|
||||||
result.push_back(0);
|
|
||||||
|
|
||||||
// Fill in the length byte from earlier
|
// Fill in the length byte from earlier
|
||||||
result[0] |= result.size() << 4;
|
result[0] |= result.size() << 4;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
#include "icsneo/communication/packet/ethphyregpacket.h"
|
||||||
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
|
#include "icsneo/communication/packetizer.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace icsneo
|
||||||
|
{
|
||||||
|
std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
|
||||||
|
{
|
||||||
|
if(bytestream.empty() || (bytestream.size() < sizeof(PhyRegisterHeader_t)))
|
||||||
|
{
|
||||||
|
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto msg = std::make_shared<EthPhyMessage>();
|
||||||
|
const PhyRegisterHeader_t* pHeader = reinterpret_cast<const PhyRegisterHeader_t*>(bytestream.data());
|
||||||
|
const size_t numEntries = static_cast<size_t>(pHeader->numEntries);
|
||||||
|
if(
|
||||||
|
(PhyPacketVersion == pHeader->version) &&
|
||||||
|
(sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) &&
|
||||||
|
(numEntries <= MaxPhyEntries) &&
|
||||||
|
((bytestream.size() - sizeof(PhyRegisterHeader_t))
|
||||||
|
== (sizeof(PhyRegisterPacket_t) * numEntries))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
msg->messages.reserve(numEntries);
|
||||||
|
const PhyRegisterPacket_t* pFirstEntry = reinterpret_cast<const PhyRegisterPacket_t*>(bytestream.data() + sizeof(PhyRegisterHeader_t));
|
||||||
|
for(size_t entryIdx{0}; entryIdx < numEntries; ++entryIdx)
|
||||||
|
{
|
||||||
|
const PhyRegisterPacket_t* pEntry = (pFirstEntry + entryIdx);
|
||||||
|
auto phyMessage = std::make_shared<PhyMessage>();
|
||||||
|
phyMessage->Enabled = (pEntry->Enabled != 0u);
|
||||||
|
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
|
||||||
|
phyMessage->Clause45Enable = (pEntry->Clause45Enable != 0u);
|
||||||
|
phyMessage->version = static_cast<uint8_t>(pEntry->version);
|
||||||
|
if(phyMessage->Clause45Enable)
|
||||||
|
phyMessage->clause45 = pEntry->clause45;
|
||||||
|
else
|
||||||
|
phyMessage->clause22 = pEntry->clause22;
|
||||||
|
msg->messages.push_back(phyMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
|
||||||
|
{
|
||||||
|
const size_t messageCount = message.getMessageCount();
|
||||||
|
if(!messageCount)
|
||||||
|
{
|
||||||
|
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (messageCount > MaxPhyEntries)
|
||||||
|
{
|
||||||
|
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto byteSize = (messageCount * sizeof(PhyRegisterPacket_t)) + sizeof(PhyRegisterHeader_t);
|
||||||
|
bytestream.reserve(byteSize);
|
||||||
|
bytestream.push_back(static_cast<uint8_t>(messageCount & 0xFF));
|
||||||
|
bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF));
|
||||||
|
bytestream.push_back(PhyPacketVersion);
|
||||||
|
bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t)));
|
||||||
|
for(auto& phyMessage : message.messages)
|
||||||
|
{
|
||||||
|
PhyRegisterPacket_t tempPacket;
|
||||||
|
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
|
||||||
|
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
|
||||||
|
tempPacket.version = (phyMessage->version & 0xF);
|
||||||
|
if(phyMessage->Clause45Enable)
|
||||||
|
{
|
||||||
|
if( (FiveBits < phyMessage->clause45.port) ||
|
||||||
|
(FiveBits < phyMessage->clause45.device) )
|
||||||
|
{
|
||||||
|
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tempPacket.Clause45Enable = 0x1u;
|
||||||
|
tempPacket.clause45.port = phyMessage->clause45.port;
|
||||||
|
tempPacket.clause45.device = phyMessage->clause45.device;
|
||||||
|
tempPacket.clause45.regAddr = phyMessage->clause45.regAddr;
|
||||||
|
tempPacket.clause45.regVal = phyMessage->clause45.regVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( (FiveBits < phyMessage->clause22.phyAddr) ||
|
||||||
|
(FiveBits < phyMessage->clause22.regAddr) )
|
||||||
|
{
|
||||||
|
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tempPacket.Clause45Enable = 0x0u;
|
||||||
|
tempPacket.clause22.phyAddr = phyMessage->clause22.phyAddr;
|
||||||
|
tempPacket.clause22.page = phyMessage->clause22.page;
|
||||||
|
tempPacket.clause22.regAddr = phyMessage->clause22.regAddr;
|
||||||
|
tempPacket.clause22.regVal = phyMessage->clause22.regVal;
|
||||||
|
}
|
||||||
|
uint8_t* pktPtr = reinterpret_cast<uint8_t*>(&tempPacket);
|
||||||
|
bytestream.insert(bytestream.end(), pktPtr, pktPtr + sizeof(PhyRegisterPacket_t));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ bool HardwareISO9141Packet::EncodeFromMessage(const ISO9141Message& message, std
|
||||||
const uint8_t maxSize = (firstPacket ? 9 : 12);
|
const uint8_t maxSize = (firstPacket ? 9 : 12);
|
||||||
uint8_t currentSize = maxSize;
|
uint8_t currentSize = maxSize;
|
||||||
if(bytesToSend - currentStart < maxSize)
|
if(bytesToSend - currentStart < maxSize)
|
||||||
currentSize = bytesToSend - currentStart;
|
currentSize = (uint8_t)(bytesToSend - currentStart);
|
||||||
|
|
||||||
packet.insert(packet.begin(), {
|
packet.insert(packet.begin(), {
|
||||||
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
(uint8_t)Network::NetID::RED, // 0x0C for long message
|
||||||
|
|
@ -75,7 +75,7 @@ bool HardwareISO9141Packet::EncodeFromMessage(const ISO9141Message& message, std
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(const std::vector<uint8_t>& bytestream) {
|
std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||||
const HardwareISO9141Packet* data = (const HardwareISO9141Packet*)bytestream.data();
|
const HardwareISO9141Packet& packet = *reinterpret_cast<const HardwareISO9141Packet*>(bytestream.data());
|
||||||
|
|
||||||
if(!mMsg) {
|
if(!mMsg) {
|
||||||
mMsg = std::make_shared<ISO9141Message>();
|
mMsg = std::make_shared<ISO9141Message>();
|
||||||
|
|
@ -84,8 +84,8 @@ std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(
|
||||||
|
|
||||||
mGotPackets++;
|
mGotPackets++;
|
||||||
|
|
||||||
const bool morePacketsComing = data->c3.frm == 0;
|
const bool morePacketsComing = packet.c3.frm == 0;
|
||||||
const uint8_t bytesInCurrentMessage = data->c3.len;
|
const uint8_t bytesInCurrentMessage = packet.c3.len;
|
||||||
if(mMsg->data.size() + bytesInCurrentMessage > 500) {
|
if(mMsg->data.size() + bytesInCurrentMessage > 500) {
|
||||||
mMsg.reset();
|
mMsg.reset();
|
||||||
return std::shared_ptr<ISO9141Message>();
|
return std::shared_ptr<ISO9141Message>();
|
||||||
|
|
@ -93,9 +93,9 @@ std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(
|
||||||
|
|
||||||
// This timestamp is raw off the device (in timestampResolution increments)
|
// This timestamp is raw off the device (in timestampResolution increments)
|
||||||
// Decoder will fix as it has information about the timestampResolution increments
|
// Decoder will fix as it has information about the timestampResolution increments
|
||||||
mMsg->timestamp = data->timestamp.TS;
|
mMsg->timestamp = packet.timestamp.TS;
|
||||||
|
|
||||||
auto* dataStart = data->data;
|
auto* dataStart = packet.data;
|
||||||
if(mGotPackets == 1) {
|
if(mGotPackets == 1) {
|
||||||
// Header
|
// Header
|
||||||
if(bytesInCurrentMessage < 3) {
|
if(bytesInCurrentMessage < 3) {
|
||||||
|
|
@ -103,31 +103,31 @@ std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(
|
||||||
return std::shared_ptr<ISO9141Message>();
|
return std::shared_ptr<ISO9141Message>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy(data->data, data->data + 3, mMsg->header.begin());
|
std::copy(packet.data, packet.data + 3, mMsg->header.begin());
|
||||||
dataStart += 3;
|
dataStart += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
mMsg->data.insert(mMsg->data.end(), dataStart, data->data + (bytesInCurrentMessage > 8 ? 8 : bytesInCurrentMessage));
|
mMsg->data.insert(mMsg->data.end(), dataStart, packet.data + (bytesInCurrentMessage > 8 ? 8 : bytesInCurrentMessage));
|
||||||
if(bytesInCurrentMessage > 8)
|
if(bytesInCurrentMessage > 8)
|
||||||
mMsg->data.push_back(data->c1.d8);
|
mMsg->data.push_back(packet.c1.d8);
|
||||||
if(bytesInCurrentMessage > 9)
|
if(bytesInCurrentMessage > 9)
|
||||||
mMsg->data.push_back(data->c2.d9);
|
mMsg->data.push_back(packet.c2.d9);
|
||||||
if(bytesInCurrentMessage > 10)
|
if(bytesInCurrentMessage > 10)
|
||||||
mMsg->data.push_back(data->c2.d10);
|
mMsg->data.push_back(packet.c2.d10);
|
||||||
if(bytesInCurrentMessage > 11)
|
if(bytesInCurrentMessage > 11)
|
||||||
mMsg->data.push_back(data->c3.d11);
|
mMsg->data.push_back(packet.c3.d11);
|
||||||
|
|
||||||
if(morePacketsComing)
|
if(morePacketsComing)
|
||||||
return std::shared_ptr<ISO9141Message>();
|
return std::shared_ptr<ISO9141Message>();
|
||||||
|
|
||||||
mMsg->transmitted = data->c1.tx;
|
mMsg->transmitted = packet.c1.tx;
|
||||||
mMsg->isInit = data->c3.init;
|
mMsg->isInit = packet.c3.init;
|
||||||
mMsg->framingError = data->c1.options & 0x1;
|
mMsg->framingError = packet.c1.options & 0x1;
|
||||||
mMsg->overflowError = data->c1.options & 0x2;
|
mMsg->overflowError = packet.c1.options & 0x2;
|
||||||
mMsg->parityError = data->c1.options & 0x4;
|
mMsg->parityError = packet.c1.options & 0x4;
|
||||||
mMsg->rxTimeoutError = data->c1.options & 0x8;
|
mMsg->rxTimeoutError = packet.c1.options & 0x8;
|
||||||
mMsg->description = data->stats;
|
mMsg->description = packet.stats;
|
||||||
|
|
||||||
auto ret = mMsg;
|
auto ret = mMsg;
|
||||||
mMsg.reset();
|
mMsg.reset();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
|
||||||
|
std::shared_ptr<LogicalDiskInfoMessage> LogicalDiskInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||||
|
// Make sure we have enough to read the packet length first
|
||||||
|
if(bytestream.size() < sizeof(LogicalDiskInfoPacket))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const LogicalDiskInfoPacket* packet = reinterpret_cast<const LogicalDiskInfoPacket*>(bytestream.data());
|
||||||
|
return std::make_shared<LogicalDiskInfoMessage>(packet->isConnected != 0, packet->numSectors, packet->hiddenSectors, packet->bytesPerSector);
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
|
||||||
if(bytestream.size() < 3) // Not enough bytes to decode
|
if(bytestream.size() < 3) // Not enough bytes to decode
|
||||||
return std::shared_ptr<VersionMessage>();
|
return std::shared_ptr<VersionMessage>();
|
||||||
|
|
||||||
auto msg = std::make_shared<VersionMessage>(true);
|
auto msg = std::make_shared<VersionMessage>(VersionMessage::MainChip);
|
||||||
|
|
||||||
msg->Versions.emplace_back();
|
msg->Versions.emplace_back();
|
||||||
optional<DeviceAppVersion>& version = msg->Versions.back();
|
optional<DeviceAppVersion>& version = msg->Versions.back();
|
||||||
|
|
@ -18,7 +18,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) {
|
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) {
|
||||||
auto msg = std::make_shared<VersionMessage>(false);
|
auto msg = std::make_shared<VersionMessage>(VersionMessage::SecondaryChips);
|
||||||
|
|
||||||
size_t bytesLeft = bytestream.size();
|
size_t bytesLeft = bytestream.size();
|
||||||
if(bytesLeft)
|
if(bytesLeft)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#include "icsneo/api/eventmanager.h"
|
#include "icsneo/api/eventmanager.h"
|
||||||
#include "icsneo/communication/command.h"
|
#include "icsneo/communication/command.h"
|
||||||
#include "icsneo/device/extensions/deviceextension.h"
|
#include "icsneo/device/extensions/deviceextension.h"
|
||||||
|
#include "icsneo/platform/optional.h"
|
||||||
|
#include "icsneo/disk/fat.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
@ -117,19 +119,16 @@ std::pair<std::vector<std::shared_ptr<Message>>, bool> Device::getMessages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) {
|
bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) {
|
||||||
// not open
|
|
||||||
if(!isOpen()) {
|
if(!isOpen()) {
|
||||||
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not online
|
|
||||||
if(!isOnline()) {
|
if(!isOnline()) {
|
||||||
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not currently polling, throw error
|
|
||||||
if(!isMessagePollingEnabled()) {
|
if(!isMessagePollingEnabled()) {
|
||||||
report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -245,19 +244,34 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
|
||||||
while(!stopHeartbeatThread) {
|
while(!stopHeartbeatThread) {
|
||||||
// Wait for 110ms for a possible heartbeat
|
// Wait for 110ms for a possible heartbeat
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(110));
|
std::this_thread::sleep_for(std::chrono::milliseconds(110));
|
||||||
if(!receivedMessage && !heartbeatSuppressed()) {
|
if(receivedMessage) {
|
||||||
|
receivedMessage = false;
|
||||||
|
} else {
|
||||||
|
// Some communication, such as the bootloader and extractor interfaces, must
|
||||||
|
// redirect the input stream from the device as it will no longer be in the
|
||||||
|
// packet format we expect here. As a result, status updates will not reach
|
||||||
|
// us here and suppressDisconnects() must be used. We don't want to request
|
||||||
|
// a status and then redirect the stream, as we'll then be polluting an
|
||||||
|
// otherwise quiet stream. This lock makes sure suppressDisconnects() will
|
||||||
|
// block until we've either gotten our status update or disconnected from
|
||||||
|
// the device.
|
||||||
|
std::lock_guard<std::mutex> lk(heartbeatMutex);
|
||||||
|
if(heartbeatSuppressed())
|
||||||
|
continue;
|
||||||
|
|
||||||
// No heartbeat received, request a status
|
// No heartbeat received, request a status
|
||||||
com->sendCommand(Command::RequestStatusUpdate);
|
com->sendCommand(Command::RequestStatusUpdate);
|
||||||
// The response should come back quickly if the com is quiet
|
// The response should come back quickly if the com is quiet
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
// Check if we got a message, and if not, if settings are being applied
|
// Check if we got a message, and if not, if settings are being applied
|
||||||
if(!receivedMessage && !heartbeatSuppressed()) {
|
if(receivedMessage) {
|
||||||
|
receivedMessage = false;
|
||||||
|
} else {
|
||||||
if(!stopHeartbeatThread && !isDisconnected())
|
if(!stopHeartbeatThread && !isDisconnected())
|
||||||
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
receivedMessage = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
com->removeMessageCallback(messageReceivedCallbackID);
|
com->removeMessageCallback(messageReceivedCallbackID);
|
||||||
|
|
@ -333,8 +347,8 @@ bool Device::goOnline() {
|
||||||
|
|
||||||
updateLEDState();
|
updateLEDState();
|
||||||
|
|
||||||
MessageFilter filter(Network::NetID::Reset_Status);
|
std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::Reset_Status);
|
||||||
filter.includeInternalInAny = true;
|
filter->includeInternalInAny = true;
|
||||||
|
|
||||||
// Wait until communication is enabled or 5 seconds, whichever comes first
|
// Wait until communication is enabled or 5 seconds, whichever comes first
|
||||||
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
|
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
|
||||||
|
|
@ -376,8 +390,8 @@ bool Device::goOffline() {
|
||||||
|
|
||||||
updateLEDState();
|
updateLEDState();
|
||||||
|
|
||||||
MessageFilter filter(Network::NetID::Reset_Status);
|
std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::Reset_Status);
|
||||||
filter.includeInternalInAny = true;
|
filter->includeInternalInAny = true;
|
||||||
|
|
||||||
// Wait until communication is disabled or 5 seconds, whichever comes first
|
// Wait until communication is disabled or 5 seconds, whichever comes first
|
||||||
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
|
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
|
||||||
|
|
@ -395,20 +409,18 @@ bool Device::goOffline() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::transmit(std::shared_ptr<Message> message) {
|
bool Device::transmit(std::shared_ptr<Frame> frame) {
|
||||||
// not open
|
|
||||||
if(!isOpen()) {
|
if(!isOpen()) {
|
||||||
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not online
|
|
||||||
if(!isOnline()) {
|
if(!isOnline()) {
|
||||||
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isSupportedTXNetwork(message->network)) {
|
if(!isSupportedTXNetwork(frame->network)) {
|
||||||
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
|
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -416,7 +428,7 @@ bool Device::transmit(std::shared_ptr<Message> message) {
|
||||||
bool extensionHookedTransmit = false;
|
bool extensionHookedTransmit = false;
|
||||||
bool transmitStatusFromExtension = false;
|
bool transmitStatusFromExtension = false;
|
||||||
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
|
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
|
||||||
if(!ext->transmitHook(message, transmitStatusFromExtension))
|
if(!ext->transmitHook(frame, transmitStatusFromExtension))
|
||||||
extensionHookedTransmit = true;
|
extensionHookedTransmit = true;
|
||||||
return !extensionHookedTransmit; // false breaks out of the loop early
|
return !extensionHookedTransmit; // false breaks out of the loop early
|
||||||
});
|
});
|
||||||
|
|
@ -424,15 +436,15 @@ bool Device::transmit(std::shared_ptr<Message> message) {
|
||||||
return transmitStatusFromExtension;
|
return transmitStatusFromExtension;
|
||||||
|
|
||||||
std::vector<uint8_t> packet;
|
std::vector<uint8_t> packet;
|
||||||
if(!com->encoder->encode(*com->packetizer, packet, message))
|
if(!com->encoder->encode(*com->packetizer, packet, frame))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return com->sendPacket(packet);
|
return com->sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::transmit(std::vector<std::shared_ptr<Message>> messages) {
|
bool Device::transmit(std::vector<std::shared_ptr<Frame>> frames) {
|
||||||
for(auto& message : messages) {
|
for(auto& frame : frames) {
|
||||||
if(!transmit(message))
|
if(!transmit(frame))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -463,6 +475,108 @@ Network Device::getNetworkByNumber(Network::Type type, size_t index) const {
|
||||||
return Network::NetID::Invalid;
|
return Network::NetID::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
if(!into || timeout <= std::chrono::milliseconds(0)) {
|
||||||
|
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isOpen()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lk(diskLock);
|
||||||
|
|
||||||
|
if(diskReadDriver->getAccess() == Disk::Access::EntireCard && diskWriteDriver->getAccess() == Disk::Access::VSA) {
|
||||||
|
// We have mismatched drivers, we need to add an offset to the diskReadDriver
|
||||||
|
const auto offset = Disk::FindVSAInFAT([this, &timeout](uint64_t pos, uint8_t *into, uint64_t amount) {
|
||||||
|
const auto start = std::chrono::steady_clock::now();
|
||||||
|
auto ret = diskReadDriver->readLogicalDisk(*com, report, pos, into, amount, timeout);
|
||||||
|
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
if(!offset.has_value())
|
||||||
|
return nullopt;
|
||||||
|
diskReadDriver->setVSAOffset(*offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is needed for certain read drivers which take over the communication stream
|
||||||
|
const auto lifetime = suppressDisconnects();
|
||||||
|
|
||||||
|
return diskReadDriver->readLogicalDisk(*com, report, pos, into, amount, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> Device::writeLogicalDisk(uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
if(!from || timeout <= std::chrono::milliseconds(0)) {
|
||||||
|
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isOpen()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lk(diskLock);
|
||||||
|
return diskWriteDriver->writeLogicalDisk(*com, report, *diskReadDriver, pos, from, amount, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<bool> Device::isLogicalDiskConnected() {
|
||||||
|
if(!isOpen()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto info = com->getLogicalDiskInfoSync();
|
||||||
|
if (!info) {
|
||||||
|
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info->connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> Device::getLogicalDiskSize() {
|
||||||
|
if(!isOpen()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto info = com->getLogicalDiskInfoSync();
|
||||||
|
if (!info) {
|
||||||
|
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info->getReportedSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> Device::getVSAOffsetInLogicalDisk() {
|
||||||
|
if(!isOpen()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lk(diskLock);
|
||||||
|
|
||||||
|
if (diskReadDriver->getAccess() == Disk::Access::VSA || diskReadDriver->getAccess() == Disk::Access::None)
|
||||||
|
return 0ull;
|
||||||
|
|
||||||
|
auto offset = Disk::FindVSAInFAT([this](uint64_t pos, uint8_t *into, uint64_t amount) {
|
||||||
|
return diskReadDriver->readLogicalDisk(*com, report, pos, into, amount);
|
||||||
|
});
|
||||||
|
if(!offset.has_value())
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(diskReadDriver->getAccess() == Disk::Access::EntireCard && diskWriteDriver->getAccess() == Disk::Access::VSA) {
|
||||||
|
// We have mismatched drivers, we need to add an offset to the diskReadDriver
|
||||||
|
diskReadDriver->setVSAOffset(*offset);
|
||||||
|
return 0ull;
|
||||||
|
}
|
||||||
|
return *offset;
|
||||||
|
}
|
||||||
|
|
||||||
optional<bool> Device::getDigitalIO(IO type, size_t number /* = 1 */) {
|
optional<bool> Device::getDigitalIO(IO type, size_t number /* = 1 */) {
|
||||||
if(number == 0) { // Start counting from 1
|
if(number == 0) { // Start counting from 1
|
||||||
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
|
@ -668,8 +782,9 @@ optional<double> Device::getAnalogIO(IO type, size_t number /* = 1 */) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Lifetime Device::suppressDisconnects() {
|
Lifetime Device::suppressDisconnects() {
|
||||||
|
std::lock_guard<std::mutex> lk(heartbeatMutex);
|
||||||
heartbeatSuppressedByUser++;
|
heartbeatSuppressedByUser++;
|
||||||
return Lifetime([this] { heartbeatSuppressedByUser--; });
|
return Lifetime([this] { std::lock_guard<std::mutex> lk2(heartbeatMutex); heartbeatSuppressedByUser--; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) {
|
void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) {
|
||||||
|
|
@ -692,22 +807,32 @@ void Device::forEachExtension(std::function<bool(const std::shared_ptr<DeviceExt
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::handleInternalMessage(std::shared_ptr<Message> message) {
|
void Device::handleInternalMessage(std::shared_ptr<Message> message) {
|
||||||
switch(message->network.getNetID()) {
|
switch(message->type) {
|
||||||
case Network::NetID::Reset_Status:
|
case Message::Type::ResetStatus:
|
||||||
latestResetStatus = std::dynamic_pointer_cast<ResetStatusMessage>(message);
|
latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message);
|
||||||
break;
|
break;
|
||||||
case Network::NetID::Device: {
|
case Message::Type::RawMessage: {
|
||||||
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
|
auto rawMessage = std::static_pointer_cast<RawMessage>(message);
|
||||||
if(canmsg)
|
switch(rawMessage->network.getNetID()) {
|
||||||
handleNeoVIMessage(std::move(canmsg));
|
case Network::NetID::Device: {
|
||||||
|
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
|
||||||
|
// if it couldn't be decoded to a CANMessage. We only care about the
|
||||||
|
// CANMessage decoding right now.
|
||||||
|
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
|
||||||
|
if(canmsg)
|
||||||
|
handleNeoVIMessage(std::move(canmsg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Network::NetID::DeviceStatus:
|
||||||
|
// Device Status format is unique per device, so the devices need to decode it themselves
|
||||||
|
handleDeviceStatus(rawMessage);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Network::NetID::DeviceStatus:
|
default: break;
|
||||||
// Device Status format is unique per device, so the devices need to decode it themselves
|
|
||||||
handleDeviceStatus(message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
|
|
||||||
}
|
}
|
||||||
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
|
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
|
||||||
ext->handleMessage(message);
|
ext->handleMessage(message);
|
||||||
|
|
@ -766,3 +891,34 @@ void Device::updateLEDState() {
|
||||||
std::vector<uint8_t> args {(uint8_t) ledState};
|
std::vector<uint8_t> args {(uint8_t) ledState};
|
||||||
com->sendCommand(Command::UpdateLEDState, args);
|
com->sendCommand(Command::UpdateLEDState, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout) {
|
||||||
|
if(!isOpen()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
if(!getEthPhyRegControlSupported()) {
|
||||||
|
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
if(!isOnline()) {
|
||||||
|
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> bytes;
|
||||||
|
HardwareEthernetPhyRegisterPacket::EncodeFromMessage(message, bytes, report);
|
||||||
|
std::shared_ptr<Message> response = com->waitForMessageSync(
|
||||||
|
[this, bytes](){ return com->sendCommand(Command::PHYControlRegisters, bytes); },
|
||||||
|
std::make_shared<MessageFilter>(Network::NetID::EthPHYControl), timeout);
|
||||||
|
|
||||||
|
if(!response) {
|
||||||
|
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
auto retMsg = std::static_pointer_cast<EthPhyMessage>(response);
|
||||||
|
if(!retMsg) {
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
return make_optional<EthPhyMessage>(*retMsg);
|
||||||
|
}
|
||||||
|
|
@ -1,265 +1,163 @@
|
||||||
#include "icsneo/device/devicefinder.h"
|
#include "icsneo/device/devicefinder.h"
|
||||||
#include "icsneo/platform/devices.h"
|
#include "icsneo/platform/devices.h"
|
||||||
|
#include "icsneo/device/founddevice.h"
|
||||||
#include "generated/extensions/builtin.h"
|
#include "generated/extensions/builtin.h"
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_FIRMIO
|
||||||
|
#include "icsneo/platform/firmio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_RAW_ETHERNET
|
||||||
|
#include "icsneo/platform/pcap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_CDCACM
|
||||||
|
#include "icsneo/platform/cdcacm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_FTDI
|
||||||
|
#include "icsneo/platform/ftdi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
static bool supportedDevicesCached = false;
|
template<typename T>
|
||||||
static std::vector<DeviceType> supportedDevices = {
|
static void makeIfSerialMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
|
||||||
|
// Relies on the subclass to have a `static constexpr const char* SERIAL_START = "XX"`
|
||||||
|
// and also a public constructor `T(const FoundDevice& dev)`
|
||||||
|
// Use macro ICSNEO_FINDABLE_DEVICE() to create these
|
||||||
|
if(dev.serial[0] == T::SERIAL_START[0] && dev.serial[1] == T::SERIAL_START[1])
|
||||||
|
into.push_back(std::make_shared<T>(dev));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __ETHERBADGE_H_
|
template<typename T>
|
||||||
EtherBADGE::DEVICE_TYPE,
|
static void makeIfPIDMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
|
||||||
#endif
|
// Relies on the subclass to have a `static constexpr uint16_t PRODUCT_ID = 0x1111`
|
||||||
|
// and also a public constructor `T(const FoundDevice& dev)`
|
||||||
#ifdef __NEOOBD2PRO_H_
|
// Use macro ICSNEO_FINDABLE_DEVICE_BY_PID() to create these
|
||||||
NeoOBD2PRO::DEVICE_TYPE,
|
if(dev.productId == T::PRODUCT_ID)
|
||||||
#endif
|
into.push_back(std::make_shared<T>(dev));
|
||||||
|
}
|
||||||
#ifdef __NEOOBD2SIM_H_
|
|
||||||
NeoOBD2SIM::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NEOVIRED2_H_
|
|
||||||
NeoVIRED2::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NEOVIFIRE_H_
|
|
||||||
NeoVIFIRE::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NEOVIFIRE2ETH_H_
|
|
||||||
NeoVIFIRE2ETH::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NEOVIFIRE2USB_H_
|
|
||||||
NeoVIFIRE2USB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NEOVIION_H_
|
|
||||||
NeoVIION::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __NEOVIPLASMA_H_
|
|
||||||
NeoVIPLASMA::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADEPSILON_H_
|
|
||||||
RADEpsilon::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADGALAXY_H_
|
|
||||||
RADGalaxy::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADGIGALOG_ETH_H_
|
|
||||||
RADGigalogETH::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADGIGALOG_USB_H_
|
|
||||||
RADGigalogUSB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADGIGASTAR_ETH_H_
|
|
||||||
RADGigastarETH::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADGIGASTAR_USB_H_
|
|
||||||
RADGigastarUSB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADMOON2_H_
|
|
||||||
RADMoon2::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADMOONDUO_H_
|
|
||||||
RADMoonDuo::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADPLUTOUSB_H_
|
|
||||||
RADPlutoUSB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADSTAR2ETH_H_
|
|
||||||
RADStar2ETH::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADSTAR2USB_H_
|
|
||||||
RADStar2USB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __RADSUPERMOON_H_
|
|
||||||
RADSupermoon::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN3_H_
|
|
||||||
ValueCAN3::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_1_H_
|
|
||||||
ValueCAN4_1::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_2_H_
|
|
||||||
ValueCAN4_2::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_2EL_ETH_H_
|
|
||||||
ValueCAN4_2EL_ETH::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_2EL_USB_H_
|
|
||||||
ValueCAN4_2EL_USB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_4_H_
|
|
||||||
ValueCAN4_4::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4INDUSTRIAL_ETH_H_
|
|
||||||
ValueCAN4IndustrialETH::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4INDUSTRIAL_USB_H_
|
|
||||||
ValueCAN4IndustrialUSB::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VIVIDCAN_H_
|
|
||||||
VividCAN::DEVICE_TYPE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
||||||
|
static std::vector<FoundDevice> driverFoundDevices;
|
||||||
|
driverFoundDevices.clear();
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_FIRMIO
|
||||||
|
FirmIO::Find(driverFoundDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_RAW_ETHERNET
|
||||||
|
PCAP::Find(driverFoundDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_CDCACM
|
||||||
|
CDCACM::Find(driverFoundDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ICSNEO_ENABLE_FTDI
|
||||||
|
FTDI::Find(driverFoundDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Device>> foundDevices;
|
std::vector<std::shared_ptr<Device>> foundDevices;
|
||||||
std::vector<std::vector<std::shared_ptr<Device>>> findResults;
|
|
||||||
|
|
||||||
#if defined(LIBICSNEO_HAVE_PCAP) && LIBICSNEO_HAVE_PCAP == 1
|
// Offer found devices to each of the subclasses
|
||||||
auto pcapDevices = PCAP::FindAll();
|
for (const FoundDevice& dev : driverFoundDevices) {
|
||||||
#endif
|
#ifdef __ETHERBADGE_H_
|
||||||
|
makeIfSerialMatches<EtherBADGE>(dev, foundDevices);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __ETHERBADGE_H_
|
#ifdef __NEOOBD2PRO_H_
|
||||||
findResults.push_back(EtherBADGE::Find());
|
makeIfSerialMatches<NeoOBD2PRO>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOOBD2PRO_H_
|
#ifdef __NEOOBD2SIM_H_
|
||||||
findResults.push_back(NeoOBD2PRO::Find());
|
makeIfSerialMatches<NeoOBD2SIM>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOOBD2SIM_H_
|
#ifdef __NEOVIFIRE_H_
|
||||||
findResults.push_back(NeoOBD2SIM::Find());
|
makeIfPIDMatches<NeoVIFIRE>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOVIFIRE_H_
|
#ifdef __NEOVIFIRE2_H_
|
||||||
findResults.push_back(NeoVIFIRE::Find());
|
makeIfSerialMatches<NeoVIFIRE2>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOVIFIRE2ETH_H_
|
#ifdef __NEOVIRED2_H_
|
||||||
findResults.push_back(NeoVIFIRE2ETH::Find(pcapDevices));
|
makeIfSerialMatches<NeoVIRED2>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOVIFIRE2USB_H_
|
#ifdef __NEOVIION_H_
|
||||||
findResults.push_back(NeoVIFIRE2USB::Find());
|
makeIfPIDMatches<NeoVIION>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOVIRED2_H_
|
#ifdef __NEOVIPLASMA_H_
|
||||||
findResults.push_back(NeoVIRED2::Find(pcapDevices));
|
makeIfPIDMatches<NeoVIPLASMA>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOVIION_H_
|
#ifdef __RADEPSILON_H_
|
||||||
findResults.push_back(NeoVIION::Find());
|
makeIfSerialMatches<RADEpsilon>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __NEOVIPLASMA_H_
|
#ifdef __RADGALAXY_H_
|
||||||
findResults.push_back(NeoVIPLASMA::Find());
|
makeIfSerialMatches<RADGalaxy>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADEPSILON_H_
|
#ifdef __RADMARS_H_
|
||||||
findResults.push_back(RADEpsilon::Find());
|
makeIfSerialMatches<RADMars>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADGALAXY_H_
|
#ifdef __RADGIGASTAR_H_
|
||||||
findResults.push_back(RADGalaxy::Find(pcapDevices));
|
makeIfSerialMatches<RADGigastar>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADGIGALOG_ETH_H_
|
#ifdef __RADMOON2_H_
|
||||||
findResults.push_back(RADGigalogETH::Find(pcapDevices));
|
makeIfSerialMatches<RADMoon2>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADGIGALOG_USB_H_
|
#ifdef __RADMOONDUO_H_
|
||||||
findResults.push_back(RADGigalogUSB::Find());
|
makeIfSerialMatches<RADMoonDuo>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADGIGASTAR_ETH_H_
|
#ifdef __RADPLUTO_H_
|
||||||
findResults.push_back(RADGigastarETH::Find(pcapDevices));
|
makeIfSerialMatches<RADPluto>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADGIGASTAR_USB_H_
|
#ifdef __RADSTAR2_H_
|
||||||
findResults.push_back(RADGigastarUSB::Find());
|
makeIfSerialMatches<RADStar2>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADMOON2_H_
|
#ifdef __RADSUPERMOON_H_
|
||||||
findResults.push_back(RADMoon2::Find());
|
makeIfSerialMatches<RADSupermoon>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADMOONDUO_H_
|
#ifdef __VALUECAN3_H_
|
||||||
findResults.push_back(RADMoonDuo::Find());
|
makeIfPIDMatches<ValueCAN3>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADPLUTOUSB_H_
|
#ifdef __VALUECAN4_1_H_
|
||||||
findResults.push_back(RADPlutoUSB::Find());
|
makeIfSerialMatches<ValueCAN4_1>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADSTAR2ETH_H_
|
#ifdef __VALUECAN4_2_H_
|
||||||
findResults.push_back(RADStar2ETH::Find(pcapDevices));
|
makeIfSerialMatches<ValueCAN4_2>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADSTAR2USB_H_
|
#ifdef __VALUECAN4_2EL_H_
|
||||||
findResults.push_back(RADStar2USB::Find());
|
makeIfSerialMatches<ValueCAN4_2EL>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __RADSUPERMOON_H_
|
#ifdef __VALUECAN4_4_H_
|
||||||
findResults.push_back(RADSupermoon::Find());
|
makeIfSerialMatches<ValueCAN4_4>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __VALUECAN3_H_
|
#ifdef __VALUECAN4INDUSTRIAL_H_
|
||||||
findResults.push_back(ValueCAN3::Find());
|
makeIfSerialMatches<ValueCAN4Industrial>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __VALUECAN4_1_H_
|
#ifdef __VIVIDCAN_H_
|
||||||
findResults.push_back(ValueCAN4_1::Find());
|
makeIfSerialMatches<VividCAN>(dev, foundDevices);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __VALUECAN4_2_H_
|
|
||||||
findResults.push_back(ValueCAN4_2::Find());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_2EL_ETH_H_
|
|
||||||
findResults.push_back(ValueCAN4_2EL_ETH::Find(pcapDevices));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_2EL_USB_H_
|
|
||||||
findResults.push_back(ValueCAN4_2EL_USB::Find());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4_4_H_
|
|
||||||
findResults.push_back(ValueCAN4_4::Find());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4INDUSTRIAL_ETH_H_
|
|
||||||
findResults.push_back(ValueCAN4IndustrialETH::Find(pcapDevices));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VALUECAN4INDUSTRIAL_USB_H_
|
|
||||||
findResults.push_back(ValueCAN4IndustrialUSB::Find());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __VIVIDCAN_H_
|
|
||||||
findResults.push_back(VividCAN::Find());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(auto& results : findResults) {
|
|
||||||
if(results.size())
|
|
||||||
foundDevices.insert(foundDevices.end(), std::make_move_iterator(results.begin()), std::make_move_iterator(results.end()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& device : foundDevices) {
|
for(auto& device : foundDevices) {
|
||||||
|
|
@ -270,9 +168,105 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
|
const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
|
||||||
if(!supportedDevicesCached) {
|
static std::vector<DeviceType> supportedDevices = {
|
||||||
supportedDevices.erase(std::unique(supportedDevices.begin(), supportedDevices.end()), supportedDevices.end());
|
|
||||||
supportedDevicesCached = true;
|
#ifdef __ETHERBADGE_H_
|
||||||
}
|
EtherBADGE::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOOBD2PRO_H_
|
||||||
|
NeoOBD2PRO::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOOBD2SIM_H_
|
||||||
|
NeoOBD2SIM::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOVIRED2_H_
|
||||||
|
NeoVIRED2::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOVIFIRE_H_
|
||||||
|
NeoVIFIRE::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOVIFIRE2_H_
|
||||||
|
NeoVIFIRE2::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOVIION_H_
|
||||||
|
NeoVIION::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NEOVIPLASMA_H_
|
||||||
|
NeoVIPLASMA::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADEPSILON_H_
|
||||||
|
RADEpsilon::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADGALAXY_H_
|
||||||
|
RADGalaxy::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADMARS_H_
|
||||||
|
RADMars::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADGIGASTAR_H_
|
||||||
|
RADGigastar::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADMOON2_H_
|
||||||
|
RADMoon2::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADMOONDUO_H_
|
||||||
|
RADMoonDuo::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADPLUTO_H_
|
||||||
|
RADPluto::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADSTAR2_H_
|
||||||
|
RADStar2::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __RADSUPERMOON_H_
|
||||||
|
RADSupermoon::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VALUECAN3_H_
|
||||||
|
ValueCAN3::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VALUECAN4_1_H_
|
||||||
|
ValueCAN4_1::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VALUECAN4_2_H_
|
||||||
|
ValueCAN4_2::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VALUECAN4_2EL_H_
|
||||||
|
ValueCAN4_2EL::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VALUECAN4_4_H_
|
||||||
|
ValueCAN4_4::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VALUECAN4INDUSTRIAL_H_
|
||||||
|
ValueCAN4Industrial::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VIVIDCAN_H_
|
||||||
|
VividCAN::DEVICE_TYPE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
return supportedDevices;
|
return supportedDevices;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
|
||||||
first->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
|
first->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
|
||||||
first->baseCycle = 0;
|
first->baseCycle = 0;
|
||||||
first->cycleRepetition = 1;
|
first->cycleRepetition = 1;
|
||||||
first->continuousMode = true;
|
first->continuousMode = false;
|
||||||
staticTx.push_back(first);
|
staticTx.push_back(first);
|
||||||
firstUsed = true;
|
firstUsed = true;
|
||||||
|
|
||||||
|
|
@ -215,7 +215,7 @@ bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
|
||||||
second->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
|
second->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
|
||||||
second->baseCycle = 0;
|
second->baseCycle = 0;
|
||||||
second->cycleRepetition = 1;
|
second->cycleRepetition = 1;
|
||||||
second->continuousMode = true;
|
second->continuousMode = false;
|
||||||
staticTx.push_back(second);
|
staticTx.push_back(second);
|
||||||
secondUsed = true;
|
secondUsed = true;
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +225,7 @@ bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
|
||||||
if(!buf->isTransmit)
|
if(!buf->isTransmit)
|
||||||
continue; // Only transmit frames need to be written to the controller
|
continue; // Only transmit frames need to be written to the controller
|
||||||
|
|
||||||
if(buf->frameID == controllerConfig.KeySlotID) {
|
if((controllerConfig.KeySlotUsedForSync || controllerConfig.KeySlotOnlyEnabled) && buf->frameID == controllerConfig.KeySlotID) {
|
||||||
first = buf;
|
first = buf;
|
||||||
staticTx[0] = buf;
|
staticTx[0] = buf;
|
||||||
// Enforce keyslot rules
|
// Enforce keyslot rules
|
||||||
|
|
@ -436,6 +436,10 @@ bool FlexRay::Controller::transmit(const std::shared_ptr<FlexRayMessage>& frmsg)
|
||||||
if(frmsg->channel != bufChannel)
|
if(frmsg->channel != bufChannel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// If we have added changed our configuration, such as adding a message buffer, we will need to reconfigure
|
||||||
|
if(configDirty && lastSeenRunning)
|
||||||
|
start();
|
||||||
|
|
||||||
// This is a message buffer we want to fill
|
// This is a message buffer we want to fill
|
||||||
if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteMessageBufferArgs(index, buf->_id, frmsg->data, buf->frameLengthBytes)))
|
if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteMessageBufferArgs(index, buf->_id, frmsg->data, buf->frameLengthBytes)))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -474,7 +478,20 @@ bool FlexRay::Controller::setCurrentPOCCommand(FlexRay::POCCommand cmd, bool che
|
||||||
const auto writeDuration = std::chrono::steady_clock::now() - beforeWrite;
|
const auto writeDuration = std::chrono::steady_clock::now() - beforeWrite;
|
||||||
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - writeDuration);
|
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - writeDuration);
|
||||||
|
|
||||||
return wasCommandSuccessful(timeout);
|
const bool success = wasCommandSuccessful(timeout);
|
||||||
|
if(success) {
|
||||||
|
switch(cmd) {
|
||||||
|
case FlexRay::POCCommand::Run:
|
||||||
|
lastSeenRunning = true;
|
||||||
|
break;
|
||||||
|
case FlexRay::POCCommand::Halt:
|
||||||
|
case FlexRay::POCCommand::Freeze:
|
||||||
|
lastSeenRunning = false;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlexRay::Controller::wasCommandSuccessful(std::chrono::milliseconds timeout) const {
|
bool FlexRay::Controller::wasCommandSuccessful(std::chrono::milliseconds timeout) const {
|
||||||
|
|
@ -593,6 +610,7 @@ uint16_t FlexRay::Controller::CalculateCycleFilter(uint8_t baseCycle, uint8_t cy
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, std::chrono::milliseconds timeout) const {
|
std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, std::chrono::milliseconds timeout) const {
|
||||||
|
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(icsneo::Network::NetID::FlexRayControl);
|
||||||
if(timeout.count() <= 20)
|
if(timeout.count() <= 20)
|
||||||
return {false, 0}; // Out of time!
|
return {false, 0}; // Out of time!
|
||||||
|
|
||||||
|
|
@ -611,7 +629,7 @@ std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, st
|
||||||
return false; // Command failed to send
|
return false; // Command failed to send
|
||||||
lastSent = std::chrono::steady_clock::now();
|
lastSent = std::chrono::steady_clock::now();
|
||||||
return true;
|
return true;
|
||||||
}, MessageFilter(icsneo::Network::NetID::FlexRayControl), timeout);
|
}, filter, timeout);
|
||||||
if(auto frmsg = std::dynamic_pointer_cast<FlexRayControlMessage>(msg)) {
|
if(auto frmsg = std::dynamic_pointer_cast<FlexRayControlMessage>(msg)) {
|
||||||
if(frmsg->decoded && frmsg->controller == index && frmsg->opcode == FlexRay::Opcode::ReadCCRegs)
|
if(frmsg->decoded && frmsg->controller == index && frmsg->opcode == FlexRay::Opcode::ReadCCRegs)
|
||||||
resp = frmsg;
|
resp = frmsg;
|
||||||
|
|
|
||||||
|
|
@ -26,18 +26,16 @@ void FlexRay::Extension::onGoOffline() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) {
|
void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) {
|
||||||
switch(message->network.getNetID()) {
|
switch(message->type) {
|
||||||
case Network::NetID::FlexRayControl: {
|
case Message::Type::FlexRayControl: {
|
||||||
auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message);
|
auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message);
|
||||||
if(!msg || !msg->decoded)
|
if(!msg || !msg->decoded)
|
||||||
return;
|
return;
|
||||||
switch(msg->opcode) {
|
switch(msg->opcode) {
|
||||||
case FlexRay::Opcode::ReadCCStatus:
|
case FlexRay::Opcode::ReadCCStatus:
|
||||||
if(auto status = std::dynamic_pointer_cast<FlexRayControlMessage>(message)) { // TODO else report error?
|
if(msg->controller >= controllers.size())
|
||||||
if(status->controller >= controllers.size())
|
return; // TODO error
|
||||||
return; // TODO error
|
controllers[msg->controller]->_setStatus(msg);
|
||||||
controllers[status->controller]->_setStatus(status);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -47,18 +45,18 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Message>& message, bool& success) {
|
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) {
|
||||||
if(!message || message->network.getType() != Network::Type::FlexRay)
|
if(!frame || frame->network.getType() != Network::Type::FlexRay)
|
||||||
return true; // Don't hook non-FlexRay messages
|
return true; // Don't hook non-FlexRay messages
|
||||||
|
|
||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(message);
|
std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(frame);
|
||||||
if(!frmsg)
|
if(!frmsg)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(auto& controller : controllers) {
|
for(auto& controller : controllers) {
|
||||||
if(controller->getNetwork() != message->network)
|
if(controller->getNetwork() != frame->network)
|
||||||
continue;
|
continue;
|
||||||
success |= controller->transmit(frmsg);
|
success |= controller->transmit(frmsg);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -228,9 +228,9 @@ bool IDeviceSettings::apply(bool temporary) {
|
||||||
// Pause I/O with the device while the settings are applied
|
// Pause I/O with the device while the settings are applied
|
||||||
applyingSettings = true;
|
applyingSettings = true;
|
||||||
|
|
||||||
std::shared_ptr<Message> msg = com->waitForMessageSync([this, &bytestream]() {
|
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
|
||||||
return com->sendCommand(Command::SetSettings, bytestream);
|
return com->sendCommand(Command::SetSettings, bytestream);
|
||||||
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000));
|
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
|
||||||
|
|
||||||
if(!msg || msg->data[0] != 1) { // We did not receive a response
|
if(!msg || msg->data[0] != 1) { // We did not receive a response
|
||||||
// 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
|
||||||
|
|
@ -254,9 +254,9 @@ bool IDeviceSettings::apply(bool temporary) {
|
||||||
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
|
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
|
||||||
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
|
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
|
||||||
|
|
||||||
msg = com->waitForMessageSync([this, &bytestream]() {
|
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
|
||||||
return com->sendCommand(Command::SetSettings, bytestream);
|
return com->sendCommand(Command::SetSettings, bytestream);
|
||||||
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000));
|
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
|
||||||
if(!msg || msg->data[0] != 1) {
|
if(!msg || msg->data[0] != 1) {
|
||||||
// Attempt to get the settings from the device so we're up to date if possible
|
// Attempt to get the settings from the device so we're up to date if possible
|
||||||
if(refresh()) {
|
if(refresh()) {
|
||||||
|
|
@ -267,9 +267,9 @@ bool IDeviceSettings::apply(bool temporary) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!temporary) {
|
if(!temporary) {
|
||||||
msg = com->waitForMessageSync([this]() {
|
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
|
||||||
return com->sendCommand(Command::SaveSettings);
|
return com->sendCommand(Command::SaveSettings);
|
||||||
}, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000));
|
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyingSettings = false;
|
applyingSettings = false;
|
||||||
|
|
@ -296,9 +296,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
|
||||||
|
|
||||||
applyingSettings = true;
|
applyingSettings = true;
|
||||||
|
|
||||||
std::shared_ptr<Message> msg = com->waitForMessageSync([this]() {
|
std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
|
||||||
return com->sendCommand(Command::SetDefaultSettings);
|
return com->sendCommand(Command::SetDefaultSettings);
|
||||||
}, Main51MessageFilter(Command::SetDefaultSettings), std::chrono::milliseconds(1000));
|
}, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000)));
|
||||||
if(!msg || msg->data[0] != 1) {
|
if(!msg || msg->data[0] != 1) {
|
||||||
// Attempt to get the settings from the device so we're up to date if possible
|
// Attempt to get the settings from the device so we're up to date if possible
|
||||||
if(refresh()) {
|
if(refresh()) {
|
||||||
|
|
@ -331,9 +331,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
|
||||||
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
|
bytestream[6] = (uint8_t)(*gsChecksum >> 8);
|
||||||
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
|
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
|
||||||
|
|
||||||
msg = com->waitForMessageSync([this, &bytestream]() {
|
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
|
||||||
return com->sendCommand(Command::SetSettings, bytestream);
|
return com->sendCommand(Command::SetSettings, bytestream);
|
||||||
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000));
|
}, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
|
||||||
if(!msg || msg->data[0] != 1) {
|
if(!msg || msg->data[0] != 1) {
|
||||||
// Attempt to get the settings from the device so we're up to date if possible
|
// Attempt to get the settings from the device so we're up to date if possible
|
||||||
if(refresh()) {
|
if(refresh()) {
|
||||||
|
|
@ -344,9 +344,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!temporary) {
|
if(!temporary) {
|
||||||
msg = com->waitForMessageSync([this]() {
|
msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
|
||||||
return com->sendCommand(Command::SaveSettings);
|
return com->sendCommand(Command::SaveSettings);
|
||||||
}, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000));
|
}, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
applyingSettings = false;
|
applyingSettings = false;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "icsneo/device/neodevice.h"
|
||||||
|
#include "icsneo/device/founddevice.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
neodevice_t::neodevice_t() : device(nullptr), handle(0), type(0) {
|
||||||
|
memset(serial, 0, sizeof(serial));
|
||||||
|
}
|
||||||
|
|
||||||
|
neodevice_t::neodevice_t(const icsneo::FoundDevice& found, devicetype_t inType)
|
||||||
|
: device(nullptr), handle(found.handle), type(inType) {
|
||||||
|
static_assert(sizeof(found.serial) == sizeof(serial), "Serial sizes should match!");
|
||||||
|
memcpy(serial, found.serial, sizeof(serial));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "icsneo/disk/diskreaddriver.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
using namespace icsneo::Disk;
|
||||||
|
|
||||||
|
optional<uint64_t> ReadDriver::readLogicalDisk(Communication& com, device_eventhandler_t report,
|
||||||
|
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
if(amount == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
optional<uint64_t> ret;
|
||||||
|
|
||||||
|
// Read into here if we can't read directly into the user buffer
|
||||||
|
// That would be the case either if we don't want some at the
|
||||||
|
// beginning or end of the block.
|
||||||
|
std::vector<uint8_t> alignedReadBuffer;
|
||||||
|
|
||||||
|
pos += vsaOffset;
|
||||||
|
const uint32_t idealBlockSize = getBlockSizeBounds().second;
|
||||||
|
const uint64_t startBlock = pos / idealBlockSize;
|
||||||
|
const uint32_t posWithinFirstBlock = static_cast<uint32_t>(pos % idealBlockSize);
|
||||||
|
uint64_t blocks = amount / idealBlockSize + (amount % idealBlockSize ? 1 : 0);
|
||||||
|
if(blocks * idealBlockSize - posWithinFirstBlock < amount)
|
||||||
|
blocks++; // We need one more block to get the last partial block's worth
|
||||||
|
uint64_t blocksProcessed = 0;
|
||||||
|
|
||||||
|
while(blocksProcessed < blocks && timeout >= std::chrono::milliseconds::zero()) {
|
||||||
|
const uint64_t currentBlock = startBlock + blocksProcessed;
|
||||||
|
|
||||||
|
uint64_t intoOffset = blocksProcessed * idealBlockSize;;
|
||||||
|
if(intoOffset < posWithinFirstBlock)
|
||||||
|
intoOffset = 0;
|
||||||
|
else
|
||||||
|
intoOffset -= posWithinFirstBlock;
|
||||||
|
|
||||||
|
const uint32_t posWithinCurrentBlock = (blocksProcessed ? 0 : posWithinFirstBlock);
|
||||||
|
uint32_t curAmt = idealBlockSize - posWithinCurrentBlock;
|
||||||
|
const auto amountLeft = amount - ret.value_or(0);
|
||||||
|
if(curAmt > amountLeft)
|
||||||
|
curAmt = static_cast<uint32_t>(amountLeft);
|
||||||
|
|
||||||
|
const bool useAlignedReadBuffer = (posWithinCurrentBlock != 0 || curAmt != idealBlockSize);
|
||||||
|
if(useAlignedReadBuffer && alignedReadBuffer.size() < idealBlockSize)
|
||||||
|
alignedReadBuffer.resize(idealBlockSize);
|
||||||
|
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
auto readAmount = readLogicalDiskAligned(com, report, currentBlock * idealBlockSize,
|
||||||
|
useAlignedReadBuffer ? alignedReadBuffer.data() : (into + intoOffset), idealBlockSize, timeout);
|
||||||
|
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
|
||||||
|
|
||||||
|
if(!readAmount.has_value() || *readAmount < curAmt) {
|
||||||
|
if(timeout < std::chrono::milliseconds::zero())
|
||||||
|
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
|
||||||
|
else
|
||||||
|
report((blocksProcessed || readAmount.value_or(0u) != 0u) ? APIEvent::Type::EOFReached :
|
||||||
|
APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(useAlignedReadBuffer)
|
||||||
|
memcpy(into + intoOffset, alignedReadBuffer.data() + posWithinCurrentBlock, curAmt);
|
||||||
|
|
||||||
|
if(!ret)
|
||||||
|
ret.emplace();
|
||||||
|
*ret += std::min<uint64_t>(*readAmount, curAmt);
|
||||||
|
blocksProcessed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include "icsneo/disk/diskwritedriver.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
using namespace icsneo::Disk;
|
||||||
|
|
||||||
|
const uint64_t WriteDriver::RetryAtomic = std::numeric_limits<uint64_t>::max();
|
||||||
|
const APIEvent::Severity WriteDriver::NonatomicSeverity = APIEvent::Severity::EventInfo;
|
||||||
|
|
||||||
|
optional<uint64_t> WriteDriver::writeLogicalDisk(Communication& com, device_eventhandler_t report, ReadDriver& readDriver,
|
||||||
|
uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
if(amount == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
optional<uint64_t> ret;
|
||||||
|
|
||||||
|
const uint32_t idealBlockSize = getBlockSizeBounds().second;
|
||||||
|
|
||||||
|
// Write from here if we need to read-modify-write a block
|
||||||
|
// That would be the case either if we don't want some at the
|
||||||
|
// beginning or end of the block.
|
||||||
|
std::vector<uint8_t> alignedWriteBuffer;
|
||||||
|
|
||||||
|
// Read to here, ideally this can be sent back to the device to
|
||||||
|
// ensure an operation is atomic
|
||||||
|
std::vector<uint8_t> atomicBuffer(idealBlockSize);
|
||||||
|
|
||||||
|
pos += vsaOffset;
|
||||||
|
const uint64_t startBlock = pos / idealBlockSize;
|
||||||
|
const uint32_t posWithinFirstBlock = static_cast<uint32_t>(pos % idealBlockSize);
|
||||||
|
uint64_t blocks = amount / idealBlockSize + (amount % idealBlockSize ? 1 : 0);
|
||||||
|
if(blocks * idealBlockSize - posWithinFirstBlock < amount)
|
||||||
|
blocks++; // We need one more block to get the last partial block's worth
|
||||||
|
uint64_t blocksProcessed = 0;
|
||||||
|
|
||||||
|
while(blocksProcessed < blocks && timeout >= std::chrono::milliseconds::zero()) {
|
||||||
|
const uint64_t currentBlock = startBlock + blocksProcessed;
|
||||||
|
|
||||||
|
uint64_t fromOffset = blocksProcessed * idealBlockSize;
|
||||||
|
if(fromOffset < posWithinFirstBlock)
|
||||||
|
fromOffset = 0;
|
||||||
|
else
|
||||||
|
fromOffset -= posWithinFirstBlock;
|
||||||
|
|
||||||
|
const uint32_t posWithinCurrentBlock = (blocksProcessed ? 0 : posWithinFirstBlock);
|
||||||
|
uint32_t curAmt = idealBlockSize - posWithinCurrentBlock;
|
||||||
|
const auto amountLeft = amount - ret.value_or(0);
|
||||||
|
if(curAmt > amountLeft)
|
||||||
|
curAmt = static_cast<uint32_t>(amountLeft);
|
||||||
|
|
||||||
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
|
const auto reportFromRead = [&report, &blocksProcessed](APIEvent::Type t, APIEvent::Severity s) {
|
||||||
|
if(t == APIEvent::Type::ParameterOutOfRange && blocksProcessed)
|
||||||
|
t = APIEvent::Type::EOFReached;
|
||||||
|
report(t, s);
|
||||||
|
};
|
||||||
|
auto bytesTransferred = readDriver.readLogicalDisk(com, reportFromRead, currentBlock * idealBlockSize,
|
||||||
|
atomicBuffer.data(), idealBlockSize, timeout);
|
||||||
|
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
|
||||||
|
|
||||||
|
if(bytesTransferred != idealBlockSize)
|
||||||
|
break; // readLogicalDisk reports its own errors
|
||||||
|
|
||||||
|
const bool useAlignedWriteBuffer = (posWithinCurrentBlock != 0 || curAmt != idealBlockSize);
|
||||||
|
if(useAlignedWriteBuffer) {
|
||||||
|
alignedWriteBuffer = atomicBuffer;
|
||||||
|
memcpy(alignedWriteBuffer.data() + posWithinCurrentBlock, from + fromOffset, curAmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = std::chrono::high_resolution_clock::now();
|
||||||
|
bytesTransferred = writeLogicalDiskAligned(com, report, currentBlock * idealBlockSize, atomicBuffer.data(),
|
||||||
|
useAlignedWriteBuffer ? alignedWriteBuffer.data() : (from + fromOffset), idealBlockSize, timeout);
|
||||||
|
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
|
||||||
|
|
||||||
|
if(bytesTransferred == RetryAtomic) {
|
||||||
|
// The user may want to log these events in order to see how many atomic misses they are getting
|
||||||
|
report(APIEvent::Type::AtomicOperationRetried, APIEvent::Severity::EventInfo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!bytesTransferred.has_value() || *bytesTransferred < curAmt) {
|
||||||
|
if(timeout < std::chrono::milliseconds::zero())
|
||||||
|
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
|
||||||
|
else
|
||||||
|
report((blocksProcessed || bytesTransferred.value_or(0u) != 0u) ? APIEvent::Type::EOFReached :
|
||||||
|
APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ret)
|
||||||
|
ret.emplace();
|
||||||
|
*ret += std::min<uint64_t>(*bytesTransferred, curAmt);
|
||||||
|
blocksProcessed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,213 @@
|
||||||
|
#include "icsneo/disk/extextractordiskreaddriver.h"
|
||||||
|
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||||
|
#include "icsneo/communication/multichannelcommunication.h"
|
||||||
|
#include "icsneo/api/lifetime.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
//#define ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
using namespace icsneo::Disk;
|
||||||
|
|
||||||
|
optional<uint64_t> ExtExtractorDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
|
||||||
|
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
|
||||||
|
if(amount > getBlockSizeBounds().second)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(amount % getBlockSizeBounds().first != 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(pos % getBlockSizeBounds().first != 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
optional<uint64_t> ret;
|
||||||
|
while(timeout > std::chrono::milliseconds(0) && !ret.has_value()) {
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
ret = attemptReadLogicalDiskAligned(com, report, pos, into, amount, std::chrono::milliseconds(100));
|
||||||
|
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligned(Communication& com, device_eventhandler_t report,
|
||||||
|
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
|
||||||
|
|
||||||
|
if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) {
|
||||||
|
uint64_t sector = pos / SectorSize;
|
||||||
|
|
||||||
|
uint64_t largeSectorCount = amount / SectorSize;
|
||||||
|
uint32_t sectorCount = uint32_t(largeSectorCount);
|
||||||
|
if (largeSectorCount != uint64_t(sectorCount))
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
// The cache does not have this data, go get it
|
||||||
|
std::mutex m;
|
||||||
|
std::condition_variable cv;
|
||||||
|
uint16_t receiving = 0; // How much are we about to get before another header or completion
|
||||||
|
uint64_t received = 0;
|
||||||
|
uint16_t receivedCurrent = 0;
|
||||||
|
size_t skipping = 0;
|
||||||
|
std::vector<uint8_t> header;
|
||||||
|
std::unique_lock<std::mutex> lk(m);
|
||||||
|
bool error = !com.redirectRead([&](std::vector<uint8_t>&& data) {
|
||||||
|
std::unique_lock<std::mutex> lk2(m);
|
||||||
|
if(error) {
|
||||||
|
lk2.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(skipping > data.size()) {
|
||||||
|
skipping -= data.size();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t offset = skipping;
|
||||||
|
skipping = 0;
|
||||||
|
while(offset < data.size()) {
|
||||||
|
size_t left = data.size() - offset;
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Going to process " << left << " bytes" << std::endl;
|
||||||
|
#endif
|
||||||
|
if(header.size() != HeaderLength) {
|
||||||
|
if(header.empty() && left && data[offset] != 0xaa) {
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Incorrect header " << int(data[offset]) << ' ' << int(offset) << std::endl;
|
||||||
|
#endif
|
||||||
|
error = true;
|
||||||
|
lk2.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Did we get a correct header and at least one byte of data?
|
||||||
|
const auto begin = data.begin() + offset;
|
||||||
|
int32_t headerLeft = int32_t(HeaderLength - header.size());
|
||||||
|
if(int32_t(left) < headerLeft) {
|
||||||
|
// Not enough data here, grab what header we can and continue
|
||||||
|
header.insert(header.end(), begin, data.end());
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Got " << int(left) << " bytes of header at " << offset << " (incomplete " <<
|
||||||
|
header.size() << ')' << std::endl;
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
header.insert(header.end(), begin, begin + headerLeft);
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Got " << int(headerLeft) << " bytes of header at " << offset << " (complete " <<
|
||||||
|
header.size() << ')' << std::endl;
|
||||||
|
#endif
|
||||||
|
offset += headerLeft;
|
||||||
|
|
||||||
|
if(header[1] == uint8_t(Network::NetID::RED)) {
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Got extended response " << int(offset) << std::endl;
|
||||||
|
#endif
|
||||||
|
// This is the extended command response, not all devices send this
|
||||||
|
// If we got it, we need to figure out how much more data to ignore
|
||||||
|
uint16_t length = (header[2] + (header[3] << 8));
|
||||||
|
// Try for another header after this, regardless how much we choose
|
||||||
|
// to skip and how we skip it
|
||||||
|
header.clear();
|
||||||
|
if(length <= 6) {
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Incorrect extended response length " << int(length) << ' ' << int(offset) << std::endl;
|
||||||
|
#endif
|
||||||
|
error = true;
|
||||||
|
lk2.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
length -= 7;
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Skipping " << int(length) << ' ' << int(left) << std::endl;
|
||||||
|
#endif
|
||||||
|
if(left < length) {
|
||||||
|
skipping = length - left;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
offset += length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The device tells us how much it's sending us before the next header
|
||||||
|
receiving = (header[5] | (header[6] << 8));
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Started packet of size " << receiving << " bytes" << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
left = data.size() - offset;
|
||||||
|
auto count = uint16_t(std::min<uint64_t>(std::min<uint64_t>(receiving - receivedCurrent, left), amount - received));
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "With " << int(left) << " bytes " << int(offset) << std::endl;
|
||||||
|
#endif
|
||||||
|
memcpy(cache.data() + received, data.data() + offset, count);
|
||||||
|
received += count;
|
||||||
|
receivedCurrent += count;
|
||||||
|
offset += count;
|
||||||
|
|
||||||
|
if(amount == received) {
|
||||||
|
if(receivedCurrent % 2 == 0)
|
||||||
|
offset++;
|
||||||
|
header.clear(); // Now we will need another header
|
||||||
|
lk2.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
lk2.lock();
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Finished!" << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(receivedCurrent == receiving) {
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Got " << count << " bytes, " << receivedCurrent << " byte packet " << received <<
|
||||||
|
" complete of " << amount << std::endl;
|
||||||
|
#endif
|
||||||
|
if(receivedCurrent % 2 == 0)
|
||||||
|
offset++;
|
||||||
|
header.clear(); // Now we will need another header
|
||||||
|
receivedCurrent = 0;
|
||||||
|
} else {
|
||||||
|
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
|
||||||
|
std::cout << "Got " << count << " bytes, incomplete (of " << receiving << " bytes)" << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Lifetime clearRedirect([&com, &lk] { lk.unlock(); com.clearRedirectRead(); });
|
||||||
|
|
||||||
|
if(error)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
error = !com.sendCommand(ExtendedCommand::Extract, {
|
||||||
|
uint8_t(sector & 0xff),
|
||||||
|
uint8_t((sector >> 8) & 0xff),
|
||||||
|
uint8_t((sector >> 16) & 0xff),
|
||||||
|
uint8_t((sector >> 24) & 0xff),
|
||||||
|
uint8_t((sector >> 32) & 0xff),
|
||||||
|
uint8_t((sector >> 40) & 0xff),
|
||||||
|
uint8_t((sector >> 48) & 0xff),
|
||||||
|
uint8_t((sector >> 56) & 0xff),
|
||||||
|
uint8_t(sectorCount & 0xff),
|
||||||
|
uint8_t((sectorCount >> 8) & 0xff),
|
||||||
|
uint8_t((sectorCount >> 16) & 0xff),
|
||||||
|
uint8_t((sectorCount >> 24) & 0xff),
|
||||||
|
});
|
||||||
|
if(error)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
bool hitTimeout = !cv.wait_for(lk, timeout, [&]() { return error || amount == received; });
|
||||||
|
if(hitTimeout || error)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
cachedAt = std::chrono::steady_clock::now();
|
||||||
|
cachePos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(into, cache.data(), size_t(amount));
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "icsneo/disk/fat.h"
|
||||||
|
#include "icsneo/disk/diskdriver.h"
|
||||||
|
#include "ff.h"
|
||||||
|
#include "diskio.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
|
||||||
|
// The FAT driver can only be accessed by one caller at a time, since it relies on globals
|
||||||
|
static std::mutex fatDriverMutex;
|
||||||
|
static std::function< optional<uint64_t>(uint64_t pos, uint8_t* into, uint64_t amount) > diskReadFn;
|
||||||
|
|
||||||
|
extern "C" DRESULT disk_read(BYTE, BYTE* buff, LBA_t sector, UINT count) {
|
||||||
|
static_assert(Disk::SectorSize == 512, "FatFs expects 512 byte sectors");
|
||||||
|
|
||||||
|
const uint64_t expected = count * uint64_t(Disk::SectorSize);
|
||||||
|
const auto res = diskReadFn(sector * uint64_t(Disk::SectorSize), buff, expected);
|
||||||
|
if (!res.has_value())
|
||||||
|
return RES_NOTRDY;
|
||||||
|
return res == expected ? RES_OK : RES_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DSTATUS disk_initialize(BYTE) {
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DSTATUS disk_status(BYTE) {
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ClusterToSector(const FATFS& fs, DWORD cluster) {
|
||||||
|
return fs.database + (LBA_t)fs.csize * (cluster - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> Disk::FindVSAInFAT(std::function< optional<uint64_t>(uint64_t pos, uint8_t* into, uint64_t amount) > diskRead) {
|
||||||
|
std::lock_guard<std::mutex> lk(fatDriverMutex);
|
||||||
|
diskReadFn = diskRead;
|
||||||
|
|
||||||
|
FATFS fs = {};
|
||||||
|
if (f_mount(&fs, (const TCHAR*)_TEXT(""), 0) != FR_OK)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
FIL logData = {};
|
||||||
|
if (f_open(&logData, (const TCHAR*)_TEXT("0:\\LOG_DATA.VSA"), FA_READ) != FR_OK)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
return ClusterToSector(fs, logData.obj.sclust) * uint64_t(Disk::SectorSize);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include "icsneo/disk/neomemorydiskdriver.h"
|
||||||
|
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
using namespace icsneo::Disk;
|
||||||
|
|
||||||
|
optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
|
||||||
|
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
|
||||||
|
|
||||||
|
if(pos % SectorSize != 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(amount != SectorSize)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) {
|
||||||
|
// The cache does not have this data, go get it
|
||||||
|
const uint64_t currentSector = pos / SectorSize;
|
||||||
|
auto msg = com.waitForMessageSync([¤tSector, &com] {
|
||||||
|
return com.sendCommand(Command::NeoReadMemory, {
|
||||||
|
MemoryTypeSD,
|
||||||
|
uint8_t(currentSector & 0xFF),
|
||||||
|
uint8_t((currentSector >> 8) & 0xFF),
|
||||||
|
uint8_t((currentSector >> 16) & 0xFF),
|
||||||
|
uint8_t((currentSector >> 24) & 0xFF),
|
||||||
|
uint8_t(SectorSize & 0xFF),
|
||||||
|
uint8_t((SectorSize >> 8) & 0xFF),
|
||||||
|
uint8_t((SectorSize >> 16) & 0xFF),
|
||||||
|
uint8_t((SectorSize >> 24) & 0xFF)
|
||||||
|
});
|
||||||
|
}, NeoMemorySDRead, timeout);
|
||||||
|
|
||||||
|
if(!msg)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const auto sdmsg = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
|
||||||
|
if(!sdmsg || sdmsg->data.size() != SectorSize) {
|
||||||
|
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(cache.data(), sdmsg->data.data(), SectorSize);
|
||||||
|
cachedAt = std::chrono::steady_clock::now();
|
||||||
|
cachePos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(into, cache.data(), SectorSize);
|
||||||
|
return SectorSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> NeoMemoryDiskDriver::writeLogicalDiskAligned(Communication& com, device_eventhandler_t report,
|
||||||
|
uint64_t pos, const uint8_t* atomicBuf, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
|
||||||
|
static std::shared_ptr<MessageFilter> NeoMemoryDone = std::make_shared<MessageFilter>(Network::NetID::NeoMemoryWriteDone);
|
||||||
|
|
||||||
|
if(pos % SectorSize != 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(amount != SectorSize)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
// Clear the cache if we're writing to the cached sector
|
||||||
|
if(pos == cachePos)
|
||||||
|
cachedAt = std::chrono::time_point<std::chrono::steady_clock>();
|
||||||
|
|
||||||
|
// Requesting an atomic operation, but neoMemory does not support it
|
||||||
|
// Continue on anyway but warn the caller
|
||||||
|
if(atomicBuf != nullptr)
|
||||||
|
report(APIEvent::Type::AtomicOperationCompletedNonatomically, NonatomicSeverity);
|
||||||
|
|
||||||
|
const uint64_t currentSector = pos / SectorSize;
|
||||||
|
auto msg = com.waitForMessageSync([¤tSector, &com, from, amount] {
|
||||||
|
std::vector<uint8_t> command = {
|
||||||
|
MemoryTypeSD,
|
||||||
|
uint8_t(currentSector & 0xFF),
|
||||||
|
uint8_t((currentSector >> 8) & 0xFF),
|
||||||
|
uint8_t((currentSector >> 16) & 0xFF),
|
||||||
|
uint8_t((currentSector >> 24) & 0xFF),
|
||||||
|
uint8_t(SectorSize & 0xFF),
|
||||||
|
uint8_t((SectorSize >> 8) & 0xFF),
|
||||||
|
};
|
||||||
|
command.insert(command.end(), from, from + amount);
|
||||||
|
return com.sendCommand(Command::NeoWriteMemory, command);
|
||||||
|
}, NeoMemoryDone, timeout);
|
||||||
|
|
||||||
|
if(!msg)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
return SectorSize;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include "icsneo/disk/nulldiskdriver.h"
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
using namespace icsneo::Disk;
|
||||||
|
|
||||||
|
optional<uint64_t> NullDriver::readLogicalDisk(Communication&, device_eventhandler_t report,
|
||||||
|
uint64_t, uint8_t*, uint64_t, std::chrono::milliseconds) {
|
||||||
|
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> NullDriver::readLogicalDiskAligned(Communication&, device_eventhandler_t report,
|
||||||
|
uint64_t, uint8_t*, uint64_t, std::chrono::milliseconds) {
|
||||||
|
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> NullDriver::writeLogicalDisk(Communication&, device_eventhandler_t report, ReadDriver&,
|
||||||
|
uint64_t, const uint8_t*, uint64_t, std::chrono::milliseconds) {
|
||||||
|
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<uint64_t> NullDriver::writeLogicalDiskAligned(Communication&, device_eventhandler_t report,
|
||||||
|
uint64_t, const uint8_t*, const uint8_t*, uint64_t, std::chrono::milliseconds) {
|
||||||
|
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
|
||||||
|
return nullopt;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#include "icsneo/disk/plasiondiskreaddriver.h"
|
||||||
|
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
|
||||||
|
#include "icsneo/communication/multichannelcommunication.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace icsneo;
|
||||||
|
using namespace icsneo::Disk;
|
||||||
|
|
||||||
|
optional<uint64_t> PlasionDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
|
||||||
|
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
|
||||||
|
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
|
||||||
|
|
||||||
|
if(amount > getBlockSizeBounds().second)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(amount % getBlockSizeBounds().first != 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(pos % getBlockSizeBounds().first != 0)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) {
|
||||||
|
uint64_t largeSector = pos / SectorSize;
|
||||||
|
uint32_t sector = uint32_t(largeSector);
|
||||||
|
if (largeSector != uint64_t(sector))
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
// The cache does not have this data, go get it
|
||||||
|
std::mutex m;
|
||||||
|
std::condition_variable cv;
|
||||||
|
uint32_t copied = 0;
|
||||||
|
bool error = false;
|
||||||
|
std::unique_lock<std::mutex> lk(m);
|
||||||
|
auto cb = com.addMessageCallback(MessageCallback([&](std::shared_ptr<Message> msg) {
|
||||||
|
std::unique_lock<std::mutex> lk(m);
|
||||||
|
|
||||||
|
const auto sdmsg = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
|
||||||
|
if(!sdmsg || cache.size() < copied + sdmsg->data.size()) {
|
||||||
|
error = true;
|
||||||
|
lk.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate the cache here in case we fail half-way through
|
||||||
|
cachedAt = std::chrono::steady_clock::time_point();
|
||||||
|
|
||||||
|
memcpy(cache.data() + copied, sdmsg->data.data(), sdmsg->data.size());
|
||||||
|
copied += uint32_t(sdmsg->data.size());
|
||||||
|
if(copied == amount) {
|
||||||
|
lk.unlock();
|
||||||
|
cv.notify_all();
|
||||||
|
}
|
||||||
|
}, NeoMemorySDRead));
|
||||||
|
|
||||||
|
com.rawWrite({
|
||||||
|
uint8_t(MultiChannelCommunication::CommandType::HostPC_from_SDCC1),
|
||||||
|
uint8_t(sector & 0xFF),
|
||||||
|
uint8_t((sector >> 8) & 0xFF),
|
||||||
|
uint8_t((sector >> 16) & 0xFF),
|
||||||
|
uint8_t((sector >> 24) & 0xFF),
|
||||||
|
uint8_t(amount & 0xFF),
|
||||||
|
uint8_t((amount >> 8) & 0xFF),
|
||||||
|
});
|
||||||
|
|
||||||
|
bool hitTimeout = !cv.wait_for(lk, timeout, [&copied, &error, &amount] { return error || copied == amount; });
|
||||||
|
com.removeMessageCallback(cb);
|
||||||
|
|
||||||
|
if(hitTimeout)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
cachedAt = std::chrono::steady_clock::now();
|
||||||
|
cachePos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(into, cache.data(), size_t(amount));
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
@ -30,13 +30,13 @@ void printAllDevices() {
|
||||||
if(numDevices == 0) {
|
if(numDevices == 0) {
|
||||||
printf("No devices found! Please scan for new devices.\n");
|
printf("No devices found! Please scan for new devices.\n");
|
||||||
}
|
}
|
||||||
for(int i = 0; i < numDevices; i++) {
|
for(size_t i = 0; i < numDevices; i++) {
|
||||||
char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = { 0 };
|
char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = { 0 };
|
||||||
size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
|
size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
|
||||||
|
|
||||||
// Updates productDescription and descriptionLength for each device
|
// Updates productDescription and descriptionLength for each device
|
||||||
if(icsneo_describeDevice(devices + i, productDescription, &descriptionLength)) {
|
if(icsneo_describeDevice(devices + i, productDescription, &descriptionLength)) {
|
||||||
printf("[%d] %s\tConnected: ", i + 1, productDescription);
|
printf("[%zd] %s\tConnected: ", i + 1, productDescription);
|
||||||
if(icsneo_isOpen(devices + i)) {
|
if(icsneo_isOpen(devices + i)) {
|
||||||
printf("Yes\t");
|
printf("Yes\t");
|
||||||
} else printf("No\t");
|
} else printf("No\t");
|
||||||
|
|
@ -52,7 +52,7 @@ void printAllDevices() {
|
||||||
} else printf("Off\n");
|
} else printf("Off\n");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
printf("Description for device %d not available!\n", i + 1);
|
printf("Description for device %zd not available!\n", i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ size_t scanNewDevices() {
|
||||||
size_t numNewDevices = 99;
|
size_t numNewDevices = 99;
|
||||||
icsneo_findAllDevices(newDevices, &numNewDevices);
|
icsneo_findAllDevices(newDevices, &numNewDevices);
|
||||||
|
|
||||||
for(int i = 0; i < numNewDevices; ++i) {
|
for(size_t i = 0; i < numNewDevices; ++i) {
|
||||||
devices[numDevices + i] = newDevices[i];
|
devices[numDevices + i] = newDevices[i];
|
||||||
}
|
}
|
||||||
numDevices += numNewDevices;
|
numDevices += numNewDevices;
|
||||||
|
|
@ -112,7 +112,7 @@ void printAPIEvents() {
|
||||||
printf("Event 0x%u: %s\n", events[0].eventNumber, events[0].description);
|
printf("Event 0x%u: %s\n", events[0].eventNumber, events[0].description);
|
||||||
} else {
|
} else {
|
||||||
printf("%d API events found!\n", (int) eventCount);
|
printf("%d API events found!\n", (int) eventCount);
|
||||||
for(int i = 0; i < eventCount; ++i) {
|
for(size_t i = 0; i < eventCount; ++i) {
|
||||||
printf("Event 0x%u: %s\n", events[i].eventNumber, events[i].description);
|
printf("Event 0x%u: %s\n", events[i].eventNumber, events[i].description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +134,7 @@ void printDeviceEvents(neodevice_t* device) {
|
||||||
printf("Event 0x%x: %s\n", events[0].eventNumber, events[0].description);
|
printf("Event 0x%x: %s\n", events[0].eventNumber, events[0].description);
|
||||||
} else {
|
} else {
|
||||||
printf("%d device events found!\n", (int) eventCount);
|
printf("%d device events found!\n", (int) eventCount);
|
||||||
for(int i = 0; i < eventCount; ++i) {
|
for(size_t i = 0; i < eventCount; ++i) {
|
||||||
printf("Event 0x%x: %s\n", events[i].eventNumber, events[i].description);
|
printf("Event 0x%x: %s\n", events[i].eventNumber, events[i].description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -196,10 +196,14 @@ const neodevice_t* selectDevice() {
|
||||||
printAllDevices();
|
printAllDevices();
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
int selectedDeviceNum = 10;
|
size_t selectedDeviceNum = 10;
|
||||||
|
|
||||||
while(selectedDeviceNum > numDevices) {
|
while(selectedDeviceNum > numDevices) {
|
||||||
char deviceSelection = getCharInput(9, '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
char deviceSelection = getCharInput(9, '1', '2', '3', '4', '5', '6', '7', '8', '9');
|
||||||
|
if(deviceSelection < '0') {
|
||||||
|
printf("Selected device out of range!\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
selectedDeviceNum = deviceSelection - '0';
|
selectedDeviceNum = deviceSelection - '0';
|
||||||
if(selectedDeviceNum > numDevices) {
|
if(selectedDeviceNum > numDevices) {
|
||||||
printf("Selected device out of range!\n");
|
printf("Selected device out of range!\n");
|
||||||
|
|
@ -301,7 +305,7 @@ int main() {
|
||||||
|
|
||||||
// Shifts everything after the removed device 1 index to the left
|
// Shifts everything after the removed device 1 index to the left
|
||||||
bool startResizing = false;
|
bool startResizing = false;
|
||||||
for(int i = 0; i < numDevices; ++i) {
|
for(size_t i = 0; i < numDevices; ++i) {
|
||||||
if(selectedDevice == devices + i)
|
if(selectedDevice == devices + i)
|
||||||
startResizing = true;
|
startResizing = true;
|
||||||
if(startResizing)
|
if(startResizing)
|
||||||
|
|
@ -467,24 +471,34 @@ int main() {
|
||||||
|
|
||||||
// Print out the received messages
|
// Print out the received messages
|
||||||
for(size_t i = 0; i < msgCount; i++) {
|
for(size_t i = 0; i < msgCount; i++) {
|
||||||
neomessage_t* msg = &msgs[i];
|
const neomessage_t* msg = &msgs[i];
|
||||||
switch(msg->type) {
|
switch(msg->messageType) {
|
||||||
case ICSNEO_NETWORK_TYPE_CAN: // CAN
|
case ICSNEO_MESSAGE_TYPE_FRAME: {
|
||||||
{
|
const neomessage_frame_t* frame = (neomessage_frame_t*)msg;
|
||||||
neomessage_can_t* canMsg = (neomessage_can_t*) msg;
|
switch(frame->type) {
|
||||||
printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length);
|
case ICSNEO_NETWORK_TYPE_CAN: {
|
||||||
for(size_t i = 0; i < canMsg->length; i++) {
|
neomessage_can_t* canMsg = (neomessage_can_t*)frame;
|
||||||
printf("%02x ", canMsg->data[i]);
|
printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length);
|
||||||
|
for(size_t i = 0; i < canMsg->length; i++) {
|
||||||
|
printf("%02x ", canMsg->data[i]);
|
||||||
|
}
|
||||||
|
if(canMsg->status.transmitMessage)
|
||||||
|
printf("TX%s %04x ", canMsg->status.globalError ? " ERR" : "", canMsg->description);
|
||||||
|
printf("(%"PRIu64")\n", canMsg->timestamp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
printf("\tMessage on netid %d with length %zu\n", frame->netid, frame->length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT: {
|
||||||
|
const neomessage_can_error_t* cec = (neomessage_can_error_t*)msg;
|
||||||
|
printf("\tCAN error counts changed, TEC=%d, REC=%d%s", cec->transmitErrorCount, cec->receiveErrorCount,
|
||||||
|
cec->status.canBusOff ? " (Bus Off)" : "");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if(canMsg->status.transmitMessage)
|
|
||||||
printf("TX%s %04x ", canMsg->status.globalError ? " ERR" : "", canMsg->description);
|
|
||||||
printf("(%"PRIu64")\n", canMsg->timestamp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if(msg->netid != 0)
|
|
||||||
printf("\tMessage on netid %d with length %zu\n", msg->netid, msg->length);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,102 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
|
||||||
return from.at(selectedDeviceNum - 1);
|
return from.at(selectedDeviceNum - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printMessage(const std::shared_ptr<icsneo::Message>& message) {
|
||||||
|
switch(message->type) {
|
||||||
|
case icsneo::Message::Type::Frame: {
|
||||||
|
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
|
||||||
|
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||||
|
switch(frame->network.getType()) {
|
||||||
|
case icsneo::Network::Type::CAN: {
|
||||||
|
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
||||||
|
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
|
||||||
|
|
||||||
|
std::cout << "\t\t" << frame->network << ' ';
|
||||||
|
if(canMessage->isCANFD) {
|
||||||
|
std::cout << "FD ";
|
||||||
|
if(!canMessage->baudrateSwitch)
|
||||||
|
std::cout << "(No BRS) ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the Arbitration ID
|
||||||
|
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
|
||||||
|
<< std::setfill('0') << canMessage->arbid;
|
||||||
|
|
||||||
|
// Print the DLC
|
||||||
|
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
|
||||||
|
|
||||||
|
// Print the data
|
||||||
|
for(auto& databyte : canMessage->data)
|
||||||
|
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
|
||||||
|
|
||||||
|
// Print the timestamp
|
||||||
|
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case icsneo::Network::Type::Ethernet: {
|
||||||
|
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
|
||||||
|
|
||||||
|
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
|
||||||
|
<< ethMessage->data.size() << " bytes on wire\n";
|
||||||
|
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
|
||||||
|
|
||||||
|
// The MACAddress may be printed directly or accessed with the `data` member
|
||||||
|
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
|
||||||
|
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
|
||||||
|
|
||||||
|
// Print the data
|
||||||
|
for(size_t i = 0; i < ethMessage->data.size(); i++) {
|
||||||
|
if(i % 8 == 0)
|
||||||
|
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
|
||||||
|
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case icsneo::Network::Type::ISO9141: {
|
||||||
|
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
|
||||||
|
// and that this example loads the device defaults at the very end.
|
||||||
|
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
|
||||||
|
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
|
||||||
|
|
||||||
|
std::cout << "\t\t" << isoMessage->network << ' ';
|
||||||
|
|
||||||
|
// Print the header bytes
|
||||||
|
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
|
||||||
|
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
|
||||||
|
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
|
||||||
|
|
||||||
|
// Print the data length
|
||||||
|
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
|
||||||
|
|
||||||
|
// Print the data
|
||||||
|
for(auto& databyte : isoMessage->data)
|
||||||
|
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
|
||||||
|
|
||||||
|
// Print the timestamp
|
||||||
|
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Ignoring non-network messages
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} // end of icsneo::Message::Type::Frame
|
||||||
|
case icsneo::Message::Type::CANErrorCount: {
|
||||||
|
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
|
||||||
|
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
|
||||||
|
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount
|
||||||
|
<< " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Ignoring other types of messages
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl;
|
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl;
|
||||||
|
|
||||||
|
|
@ -392,28 +488,8 @@ int main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print out the received messages
|
// Print out the received messages
|
||||||
for(auto msg : msgs) {
|
for(const auto& msg : msgs)
|
||||||
switch(msg->network.getType()) {
|
printMessage(msg);
|
||||||
case icsneo::Network::Type::CAN:
|
|
||||||
{
|
|
||||||
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
|
||||||
auto canMsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
|
|
||||||
std::cout << "\t0x" << std::setfill('0') << std::setw(3) << std::hex << (int) canMsg->arbid << " [" << canMsg->data.size() << "] " << std::dec;
|
|
||||||
|
|
||||||
for(auto data : canMsg->data) {
|
|
||||||
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int) data << " " << std::dec;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << canMsg->timestamp << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if(msg->network.getNetID() != icsneo::Network::NetID::Device) {
|
|
||||||
std::cout << "\tMessage on netid " << msg->network.GetNetIDString(msg->network.getNetID()) << " with length " << msg->data.size() << std::endl;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
@ -538,28 +614,8 @@ int main() {
|
||||||
switch(selection) {
|
switch(selection) {
|
||||||
case '1':
|
case '1':
|
||||||
{
|
{
|
||||||
// Shameless copy-paste from get messages above, demonstrating a callback
|
|
||||||
int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){
|
int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){
|
||||||
switch(msg->network.getType()) {
|
printMessage(msg);
|
||||||
case icsneo::Network::Type::CAN:
|
|
||||||
{
|
|
||||||
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
|
||||||
auto canMsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
|
|
||||||
std::cout << "\t0x" << std::setfill('0') << std::setw(3) << std::hex << (int) canMsg->arbid << " [" << canMsg->data.size() << "] " << std::dec;
|
|
||||||
|
|
||||||
for(auto data : canMsg->data) {
|
|
||||||
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int) data << " " << std::dec;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << canMsg->timestamp << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if(msg->network.getNetID() != icsneo::Network::NetID::Device) {
|
|
||||||
std::cout << "\tMessage on netid " << msg->network.GetNetIDString(msg->network.getNetID()) << " with length " << msg->data.size() << std::endl;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if(callbackID != -1) {
|
if(callbackID != -1) {
|
||||||
|
|
@ -636,7 +692,7 @@ int main() {
|
||||||
names.push_back("Ethernet (DoIP) Activation Line");
|
names.push_back("Ethernet (DoIP) Activation Line");
|
||||||
if(ethAct > 1) {
|
if(ethAct > 1) {
|
||||||
names.back() += ' ';
|
names.back() += ' ';
|
||||||
names.back() += i;
|
names.back() += std::to_string(i);
|
||||||
}
|
}
|
||||||
std::cout << '[' << options.back() << "] " << names.back();
|
std::cout << '[' << options.back() << "] " << names.back();
|
||||||
const auto val = selectedDevice->getDigitalIO(icsneo::IO::EthernetActivation, i);
|
const auto val = selectedDevice->getDigitalIO(icsneo::IO::EthernetActivation, i);
|
||||||
|
|
@ -655,7 +711,7 @@ int main() {
|
||||||
names.push_back("USB Host Power");
|
names.push_back("USB Host Power");
|
||||||
if(usbHost > 1) {
|
if(usbHost > 1) {
|
||||||
names.back() += ' ';
|
names.back() += ' ';
|
||||||
names.back() += i;
|
names.back() += std::to_string(i);
|
||||||
}
|
}
|
||||||
std::cout << '[' << options.back() << "] " << names.back();
|
std::cout << '[' << options.back() << "] " << names.back();
|
||||||
const auto val = selectedDevice->getDigitalIO(icsneo::IO::USBHostPower, i);
|
const auto val = selectedDevice->getDigitalIO(icsneo::IO::USBHostPower, i);
|
||||||
|
|
|
||||||
|
|
@ -126,82 +126,118 @@ int main() {
|
||||||
device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k
|
device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k
|
||||||
// Keep in mind that 20k messages comes quickly at high bus loads!
|
// Keep in mind that 20k messages comes quickly at high bus loads!
|
||||||
|
|
||||||
|
// We can transmit messages
|
||||||
|
std::cout << "\tTransmitting an extended CAN FD frame... ";
|
||||||
|
auto txMessage5 = std::make_shared<icsneo::CANMessage>();
|
||||||
|
txMessage5->network = icsneo::Network::NetID::HSCAN;
|
||||||
|
txMessage5->arbid = 0x1C5001C5;
|
||||||
|
txMessage5->data.insert(txMessage5->data.end(), {0xaa, 0xbb, 0xcc});
|
||||||
|
// The DLC will come from the length of the data vector
|
||||||
|
txMessage5->isExtended = true;
|
||||||
|
txMessage5->isCANFD = true;
|
||||||
|
ret = device->transmit(txMessage5); // This will return false if the device does not support CAN FD, or does not have HSCAN
|
||||||
|
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||||
|
|
||||||
// We can also register a handler
|
// We can also register a handler
|
||||||
std::cout << "\tStreaming messages in for 3 seconds... " << std::endl;
|
std::cout << "\tStreaming messages in for 3 seconds... " << std::endl;
|
||||||
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
|
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
|
||||||
auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) {
|
auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) {
|
||||||
switch(message->network.getType()) {
|
switch(message->type) {
|
||||||
case icsneo::Network::Type::CAN: {
|
case icsneo::Message::Type::Frame: {
|
||||||
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
|
||||||
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
|
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
|
||||||
|
switch(frame->network.getType()) {
|
||||||
|
case icsneo::Network::Type::CAN: {
|
||||||
|
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
|
||||||
|
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
|
||||||
|
|
||||||
std::cout << "\t\tCAN ";
|
std::cout << "\t\t" << frame->network << ' ';
|
||||||
if(canMessage->isCANFD) {
|
if(canMessage->isCANFD) {
|
||||||
std::cout << "FD ";
|
std::cout << "FD ";
|
||||||
if(!canMessage->baudrateSwitch)
|
if(!canMessage->baudrateSwitch)
|
||||||
std::cout << "(No BRS) ";
|
std::cout << "(No BRS) ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the Arbitration ID
|
||||||
|
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
|
||||||
|
<< std::setfill('0') << canMessage->arbid;
|
||||||
|
|
||||||
|
// Print the DLC
|
||||||
|
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
|
||||||
|
|
||||||
|
// Print the data
|
||||||
|
for(auto& databyte : canMessage->data)
|
||||||
|
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
|
||||||
|
|
||||||
|
// Print the timestamp
|
||||||
|
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case icsneo::Network::Type::Ethernet: {
|
||||||
|
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
|
||||||
|
|
||||||
|
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
|
||||||
|
<< ethMessage->data.size() << " bytes on wire\n";
|
||||||
|
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
|
||||||
|
|
||||||
|
// The MACAddress may be printed directly or accessed with the `data` member
|
||||||
|
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
|
||||||
|
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
|
||||||
|
|
||||||
|
// Print the data
|
||||||
|
for(size_t i = 0; i < ethMessage->data.size(); i++) {
|
||||||
|
if(i % 8 == 0)
|
||||||
|
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
|
||||||
|
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case icsneo::Network::Type::ISO9141: {
|
||||||
|
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
|
||||||
|
// and that this example loads the device defaults at the very end.
|
||||||
|
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
|
||||||
|
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
|
||||||
|
|
||||||
|
std::cout << "\t\t" << isoMessage->network << ' ';
|
||||||
|
|
||||||
|
// Print the header bytes
|
||||||
|
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
|
||||||
|
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
|
||||||
|
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
|
||||||
|
|
||||||
|
// Print the data length
|
||||||
|
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
|
||||||
|
|
||||||
|
// Print the data
|
||||||
|
for(auto& databyte : isoMessage->data)
|
||||||
|
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
|
||||||
|
|
||||||
|
// Print the timestamp
|
||||||
|
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// Ignoring non-network messages
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
} // end of icsneo::Message::Type::Frame
|
||||||
|
case icsneo::Message::Type::CANErrorCount: {
|
||||||
|
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
|
||||||
|
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
|
||||||
|
|
||||||
// Print the Arbitration ID
|
// Print the error counts
|
||||||
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3) << std::setfill('0') << canMessage->arbid;
|
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount)
|
||||||
|
<< " TEC=" << std::to_string(cec->transmitErrorCount) << " (" << (cec->busOff ? "" : "Not ") << "Bus Off) ";
|
||||||
// Print the DLC
|
|
||||||
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
|
|
||||||
|
|
||||||
// Print the data
|
|
||||||
for(auto& databyte : canMessage->data)
|
|
||||||
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
|
|
||||||
|
|
||||||
// Print the timestamp
|
// Print the timestamp
|
||||||
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n";
|
std::cout << std::dec << '(' << cec->timestamp << " ns since 1/1/2007)\n";
|
||||||
break;
|
|
||||||
}
|
|
||||||
case icsneo::Network::Type::Ethernet: {
|
|
||||||
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
|
|
||||||
|
|
||||||
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec << ethMessage->data.size() << " bytes on wire\n";
|
|
||||||
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
|
|
||||||
|
|
||||||
// The MACAddress may be printed directly or accessed with the `data` member
|
|
||||||
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
|
|
||||||
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
|
|
||||||
|
|
||||||
// Print the data
|
|
||||||
for(size_t i = 0; i < ethMessage->data.size(); i++) {
|
|
||||||
if(i % 8 == 0)
|
|
||||||
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
|
|
||||||
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::dec << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case icsneo::Network::Type::ISO9141: {
|
|
||||||
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
|
|
||||||
// and that this example loads the device defaults at the very end.
|
|
||||||
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
|
|
||||||
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
|
|
||||||
|
|
||||||
std::cout << "\t\t" << isoMessage->network << ' ';
|
|
||||||
|
|
||||||
// Print the header bytes
|
|
||||||
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
|
|
||||||
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
|
|
||||||
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
|
|
||||||
|
|
||||||
// Print the data length
|
|
||||||
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
|
|
||||||
|
|
||||||
// Print the data
|
|
||||||
for(auto& databyte : isoMessage->data)
|
|
||||||
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
|
|
||||||
|
|
||||||
// Print the timestamp
|
|
||||||
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Ignoring non-network messages
|
// Ignoring other types of messages
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ public:
|
||||||
UnsupportedTXNetwork = 0x1011,
|
UnsupportedTXNetwork = 0x1011,
|
||||||
MessageMaxLengthExceeded = 0x1012,
|
MessageMaxLengthExceeded = 0x1012,
|
||||||
ValueNotYetPresent = 0x1013,
|
ValueNotYetPresent = 0x1013,
|
||||||
|
Timeout = 0x1014,
|
||||||
|
|
||||||
// Device Events
|
// Device Events
|
||||||
PollingMessageOverflow = 0x2000,
|
PollingMessageOverflow = 0x2000,
|
||||||
|
|
@ -79,6 +80,12 @@ public:
|
||||||
NoSerialNumberFW = 0x2027, // A firmware update was already attempted
|
NoSerialNumberFW = 0x2027, // A firmware update was already attempted
|
||||||
NoSerialNumber12V = 0x2028, // The device must be powered with 12V for communication to be established
|
NoSerialNumber12V = 0x2028, // The device must be powered with 12V for communication to be established
|
||||||
NoSerialNumberFW12V = 0x2029, // The device must be powered with 12V for communication to be established, a firmware update was already attempted
|
NoSerialNumberFW12V = 0x2029, // The device must be powered with 12V for communication to be established, a firmware update was already attempted
|
||||||
|
EthPhyRegisterControlNotAvailable = 0x2030, //The device doesn't support Ethernet PHY MDIO access
|
||||||
|
DiskNotSupported = 0x2031,
|
||||||
|
EOFReached = 0x2032,
|
||||||
|
SettingsDefaultsUsed = 0x2033,
|
||||||
|
AtomicOperationRetried = 0x2034,
|
||||||
|
AtomicOperationCompletedNonatomically = 0x2035,
|
||||||
|
|
||||||
// Transport Events
|
// Transport Events
|
||||||
FailedToRead = 0x3000,
|
FailedToRead = 0x3000,
|
||||||
|
|
|
||||||
|
|
@ -29,28 +29,10 @@ public:
|
||||||
|
|
||||||
// If this thread is not in the map, add it to be ignored
|
// If this thread is not in the map, add it to be ignored
|
||||||
// If it is, set it to be ignored
|
// If it is, set it to be ignored
|
||||||
void downgradeErrorsOnCurrentThread() {
|
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
|
// If this thread exists in the map, turn off downgrading
|
||||||
void cancelErrorDowngradingOnCurrentThread() {
|
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;
|
bool isDowngradingErrorsOnCurrentThread() const;
|
||||||
|
|
||||||
|
|
@ -59,7 +41,7 @@ public:
|
||||||
|
|
||||||
size_t eventCount(EventFilter filter = EventFilter()) const {
|
size_t eventCount(EventFilter filter = EventFilter()) const {
|
||||||
std::lock_guard<std::mutex> lk(eventsMutex);
|
std::lock_guard<std::mutex> lk(eventsMutex);
|
||||||
return count_internal(filter);
|
return countInternal(filter);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<APIEvent> get(EventFilter filter, size_t max = 0) { return get(max, filter); }
|
std::vector<APIEvent> get(EventFilter filter, size_t max = 0) { return get(max, filter); }
|
||||||
|
|
@ -73,65 +55,23 @@ public:
|
||||||
|
|
||||||
APIEvent getLastError();
|
APIEvent getLastError();
|
||||||
|
|
||||||
void add(APIEvent event) {
|
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) {
|
void add(APIEvent::Type type, APIEvent::Severity severity, const Device* forDevice = nullptr) {
|
||||||
add(APIEvent(type, severity, forDevice));
|
add(APIEvent(type, severity, forDevice));
|
||||||
}
|
}
|
||||||
|
|
||||||
void discard(EventFilter filter = EventFilter());
|
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 {
|
size_t getEventLimit() const {
|
||||||
std::lock_guard<std::mutex> lk(eventLimitMutex);
|
std::lock_guard<std::mutex> lk(eventLimitMutex);
|
||||||
return eventLimit;
|
return eventLimit;
|
||||||
}
|
}
|
||||||
|
void setEventLimit(size_t newLimit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventManager() : eventsMutex(), errorsMutex(), downgradedThreadsMutex(), callbacksMutex(), callbackIDMutex(), eventLimitMutex(), downgradedThreads(), callbacks(), events(), lastUserErrors(), eventLimit(10000) {}
|
EventManager() : eventLimit(10000) {}
|
||||||
EventManager(const EventManager &other);
|
EventManager(const EventManager& other); // = delete (not supported everywhere)
|
||||||
EventManager& operator=(const EventManager &other);
|
EventManager& operator=(const EventManager& other); // = delete (not supported everywhere)
|
||||||
|
|
||||||
// Used by functions for threadsafety
|
// Used by functions for threadsafety
|
||||||
mutable std::mutex eventsMutex;
|
mutable std::mutex eventsMutex;
|
||||||
|
|
@ -155,51 +95,15 @@ private:
|
||||||
std::map<std::thread::id, APIEvent> lastUserErrors;
|
std::map<std::thread::id, APIEvent> lastUserErrors;
|
||||||
size_t eventLimit = 10000;
|
size_t eventLimit = 10000;
|
||||||
|
|
||||||
size_t count_internal(EventFilter filter = EventFilter()) const;
|
size_t countInternal(EventFilter filter = EventFilter()) const;
|
||||||
|
|
||||||
void runCallbacks(APIEvent event) {
|
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
|
* 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)
|
* 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) {
|
void addEventInternal(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
|
bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ namespace icsneo {
|
||||||
enum class Command : uint8_t {
|
enum class Command : uint8_t {
|
||||||
EnableNetworkCommunication = 0x07,
|
EnableNetworkCommunication = 0x07,
|
||||||
EnableNetworkCommunicationEx = 0x08,
|
EnableNetworkCommunicationEx = 0x08,
|
||||||
|
NeoReadMemory = 0x40,
|
||||||
|
NeoWriteMemory = 0x41,
|
||||||
RequestSerialNumber = 0xA1,
|
RequestSerialNumber = 0xA1,
|
||||||
GetMainVersion = 0xA3, // Previously known as RED_CMD_APP_VERSION_REQ
|
GetMainVersion = 0xA3, // Previously known as RED_CMD_APP_VERSION_REQ
|
||||||
SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM
|
SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM
|
||||||
|
|
@ -16,13 +18,27 @@ enum class Command : uint8_t {
|
||||||
UpdateLEDState = 0xA7,
|
UpdateLEDState = 0xA7,
|
||||||
SetDefaultSettings = 0xA8, // Follow up with SaveSettings to write to EEPROM
|
SetDefaultSettings = 0xA8, // Follow up with SaveSettings to write to EEPROM
|
||||||
GetSecondaryVersions = 0xA9, // Previously known as RED_CMD_PERIPHERALS_APP_VERSION_REQ, versions other than the main chip
|
GetSecondaryVersions = 0xA9, // Previously known as RED_CMD_PERIPHERALS_APP_VERSION_REQ, versions other than the main chip
|
||||||
|
GetLogicalDiskInfo = 0xBB, // Previously known as RED_CMD_GET_SDCARD_INFO
|
||||||
RequestStatusUpdate = 0xBC,
|
RequestStatusUpdate = 0xBC,
|
||||||
ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX
|
ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX
|
||||||
SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR
|
SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR
|
||||||
RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH
|
RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH
|
||||||
GetVBattReq = 0xDF, // Previously known as RED_CMD_VBATT_REQUEST
|
GetVBattReq = 0xDF, // Previously known as RED_CMD_VBATT_REQUEST
|
||||||
MiscControl = 0xE7,
|
MiscControl = 0xE7,
|
||||||
FlexRayControl = 0xF3
|
Extended = 0xF0,
|
||||||
|
FlexRayControl = 0xF3,
|
||||||
|
PHYControlRegisters = 0xEF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ExtendedCommand : uint16_t {
|
||||||
|
GetDiskDetails = 0x0010,
|
||||||
|
DiskFormatStart = 0x0011,
|
||||||
|
DiskFormatCancel = 0x0012,
|
||||||
|
DiskFormatProgress = 0x0013,
|
||||||
|
DiskFormatUpdate = 0x0014,
|
||||||
|
Extract = 0x0015,
|
||||||
|
StartDHCPServer = 0x0016,
|
||||||
|
StopDHCPServer = 0x0017,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "icsneo/communication/packet.h"
|
#include "icsneo/communication/packet.h"
|
||||||
#include "icsneo/communication/message/callback/messagecallback.h"
|
#include "icsneo/communication/message/callback/messagecallback.h"
|
||||||
#include "icsneo/communication/message/serialnumbermessage.h"
|
#include "icsneo/communication/message/serialnumbermessage.h"
|
||||||
|
#include "icsneo/communication/message/logicaldiskinfomessage.h"
|
||||||
#include "icsneo/device/deviceversion.h"
|
#include "icsneo/device/deviceversion.h"
|
||||||
#include "icsneo/api/eventmanager.h"
|
#include "icsneo/api/eventmanager.h"
|
||||||
#include "icsneo/communication/packetizer.h"
|
#include "icsneo/communication/packetizer.h"
|
||||||
|
|
@ -25,14 +26,14 @@ namespace icsneo {
|
||||||
|
|
||||||
class Communication {
|
class Communication {
|
||||||
public:
|
public:
|
||||||
|
// Note that the Packetizer is not created by the constructor,
|
||||||
|
// and should be done once the Communication module is in place.
|
||||||
Communication(
|
Communication(
|
||||||
device_eventhandler_t report,
|
device_eventhandler_t report,
|
||||||
std::unique_ptr<Driver>&& driver,
|
std::unique_ptr<Driver>&& driver,
|
||||||
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer,
|
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer,
|
||||||
std::unique_ptr<Encoder>&& e,
|
std::unique_ptr<Encoder>&& e,
|
||||||
std::unique_ptr<Decoder>&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), report(report), driver(std::move(driver)) {
|
std::unique_ptr<Decoder>&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), driver(std::move(driver)), report(report) {}
|
||||||
packetizer = makeConfiguredPacketizer();
|
|
||||||
}
|
|
||||||
virtual ~Communication();
|
virtual ~Communication();
|
||||||
|
|
||||||
bool open();
|
bool open();
|
||||||
|
|
@ -52,14 +53,16 @@ public:
|
||||||
|
|
||||||
virtual bool sendCommand(Command cmd, bool boolean) { return sendCommand(cmd, std::vector<uint8_t>({ (uint8_t)boolean })); }
|
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 = {});
|
virtual bool sendCommand(Command cmd, std::vector<uint8_t> arguments = {});
|
||||||
|
bool sendCommand(ExtendedCommand cmd, std::vector<uint8_t> arguments = {});
|
||||||
bool getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
bool getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
std::shared_ptr<SerialNumberMessage> getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
std::shared_ptr<SerialNumberMessage> getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
optional< std::vector< optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
optional< std::vector< optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
|
std::shared_ptr<LogicalDiskInfoMessage> getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
|
|
||||||
int addMessageCallback(const MessageCallback& cb);
|
int addMessageCallback(const MessageCallback& cb);
|
||||||
bool removeMessageCallback(int id);
|
bool removeMessageCallback(int id);
|
||||||
std::shared_ptr<Message> waitForMessageSync(
|
std::shared_ptr<Message> waitForMessageSync(
|
||||||
MessageFilter f = MessageFilter(),
|
const std::shared_ptr<MessageFilter>& f = {},
|
||||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) {
|
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) {
|
||||||
return waitForMessageSync([](){ return true; }, f, timeout);
|
return waitForMessageSync([](){ return true; }, f, timeout);
|
||||||
}
|
}
|
||||||
|
|
@ -67,17 +70,17 @@ public:
|
||||||
// Return false to bail early, in case your initial command failed.
|
// Return false to bail early, in case your initial command failed.
|
||||||
std::shared_ptr<Message> waitForMessageSync(
|
std::shared_ptr<Message> waitForMessageSync(
|
||||||
std::function<bool(void)> onceWaitingDo,
|
std::function<bool(void)> onceWaitingDo,
|
||||||
MessageFilter f = MessageFilter(),
|
const std::shared_ptr<MessageFilter>& f = {},
|
||||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
|
|
||||||
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer;
|
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer;
|
||||||
std::unique_ptr<Packetizer> packetizer;
|
std::unique_ptr<Packetizer> packetizer;
|
||||||
std::unique_ptr<Encoder> encoder;
|
std::unique_ptr<Encoder> encoder;
|
||||||
std::unique_ptr<Decoder> decoder;
|
std::unique_ptr<Decoder> decoder;
|
||||||
|
std::unique_ptr<Driver> driver;
|
||||||
device_eventhandler_t report;
|
device_eventhandler_t report;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<Driver> driver;
|
|
||||||
static int messageCallbackIDCounter;
|
static int messageCallbackIDCounter;
|
||||||
std::mutex messageCallbacksLock;
|
std::mutex messageCallbacksLock;
|
||||||
std::map<int, MessageCallback> messageCallbacks;
|
std::map<int, MessageCallback> messageCallbacks;
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,10 @@ public:
|
||||||
virtual void awaitModeChangeComplete() {}
|
virtual void awaitModeChangeComplete() {}
|
||||||
virtual bool isDisconnected() { return disconnected; };
|
virtual bool isDisconnected() { return disconnected; };
|
||||||
virtual bool close() = 0;
|
virtual bool close() = 0;
|
||||||
virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
|
bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
|
||||||
virtual bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0);
|
bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0);
|
||||||
virtual bool write(const std::vector<uint8_t>& bytes);
|
bool write(const std::vector<uint8_t>& bytes);
|
||||||
|
virtual bool isEthernet() const { return false; }
|
||||||
|
|
||||||
device_eventhandler_t report;
|
device_eventhandler_t report;
|
||||||
|
|
||||||
|
|
@ -44,8 +45,15 @@ protected:
|
||||||
LAUNCH,
|
LAUNCH,
|
||||||
WAIT
|
WAIT
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void readTask() = 0;
|
virtual void readTask() = 0;
|
||||||
virtual void writeTask() = 0;
|
virtual void writeTask() = 0;
|
||||||
|
|
||||||
|
// Overridable in case the driver doesn't want to use writeTask and writeQueue
|
||||||
|
virtual bool writeQueueFull() { return writeQueue.size_approx() > writeQueueSize; }
|
||||||
|
virtual bool writeQueueAlmostFull() { return writeQueue.size_approx() > (writeQueueSize * 3 / 4); }
|
||||||
|
virtual bool writeInternal(const std::vector<uint8_t>& b) { return writeQueue.enqueue(WriteOperation(b)); }
|
||||||
|
|
||||||
moodycamel::BlockingConcurrentQueue<uint8_t> readQueue;
|
moodycamel::BlockingConcurrentQueue<uint8_t> readQueue;
|
||||||
moodycamel::BlockingConcurrentQueue<WriteOperation> writeQueue;
|
moodycamel::BlockingConcurrentQueue<WriteOperation> writeQueue;
|
||||||
std::thread readThread, writeThread;
|
std::thread readThread, writeThread;
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,11 @@ class Encoder {
|
||||||
public:
|
public:
|
||||||
Encoder(device_eventhandler_t report) : report(report) {}
|
Encoder(device_eventhandler_t report) : report(report) {}
|
||||||
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message);
|
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message);
|
||||||
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, bool boolean) {
|
|
||||||
return encode(packetizer, result, cmd, std::vector<uint8_t>({ (uint8_t)boolean }));
|
|
||||||
}
|
|
||||||
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments = {});
|
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments = {});
|
||||||
|
|
||||||
bool supportCANFD = false;
|
bool supportCANFD = false;
|
||||||
|
bool supportEthPhy = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
device_eventhandler_t report;
|
device_eventhandler_t report;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ namespace icsneo {
|
||||||
*/
|
*/
|
||||||
class EthernetPacketizer {
|
class EthernetPacketizer {
|
||||||
public:
|
public:
|
||||||
|
static const size_t MaxPacketLength;
|
||||||
|
|
||||||
EthernetPacketizer(device_eventhandler_t report) : report(report) {}
|
EthernetPacketizer(device_eventhandler_t report) : report(report) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -25,7 +27,7 @@ public:
|
||||||
* outputDown to get the results. Passing in multiple
|
* outputDown to get the results. Passing in multiple
|
||||||
* packets may result in better packing.
|
* packets may result in better packing.
|
||||||
*/
|
*/
|
||||||
void inputDown(std::vector<uint8_t> bytes);
|
void inputDown(std::vector<uint8_t> bytes, bool first = true);
|
||||||
std::vector< std::vector<uint8_t> > outputDown();
|
std::vector< std::vector<uint8_t> > outputDown();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -47,6 +49,7 @@ public:
|
||||||
uint8_t srcMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF };
|
uint8_t srcMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF };
|
||||||
uint16_t etherType = 0xCAB1; // Big endian, Should be 0xCAB1 or 0xCAB2
|
uint16_t etherType = 0xCAB1; // Big endian, Should be 0xCAB1 or 0xCAB2
|
||||||
uint32_t icsEthernetHeader = 0xAAAA5555; // Big endian, Should be 0xAAAA5555
|
uint32_t icsEthernetHeader = 0xAAAA5555; // Big endian, Should be 0xAAAA5555
|
||||||
|
uint16_t payloadSize = 0; // If this is a multi-piece message, this is the size of the expected reassembly
|
||||||
// At this point in the packet, there is a 16-bit payload size, little endian
|
// At this point in the packet, there is a 16-bit payload size, little endian
|
||||||
// This is calculated from payload size in getBytestream
|
// This is calculated from payload size in getBytestream
|
||||||
uint16_t packetNumber = 0;
|
uint16_t packetNumber = 0;
|
||||||
|
|
@ -58,6 +61,7 @@ public:
|
||||||
|
|
||||||
uint8_t hostMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF };
|
uint8_t hostMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF };
|
||||||
uint8_t deviceMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
uint8_t deviceMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
bool allowInPacketsFromAnyMAC = false; // Used when discovering devices
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool reassembling = false;
|
bool reassembling = false;
|
||||||
|
|
@ -66,9 +70,11 @@ private:
|
||||||
uint16_t sequenceDown = 0;
|
uint16_t sequenceDown = 0;
|
||||||
|
|
||||||
std::vector<uint8_t> processedUpBytes;
|
std::vector<uint8_t> processedUpBytes;
|
||||||
std::vector< std::vector<uint8_t> > processedDownPackets;
|
std::vector<EthernetPacket> processedDownPackets;
|
||||||
|
|
||||||
device_eventhandler_t report;
|
device_eventhandler_t report;
|
||||||
|
|
||||||
|
EthernetPacket& newSendPacket(bool first);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,20 @@ class MessageCallback {
|
||||||
public:
|
public:
|
||||||
typedef std::function< void( std::shared_ptr<Message> ) > fn_messageCallback;
|
typedef std::function< void( std::shared_ptr<Message> ) > fn_messageCallback;
|
||||||
|
|
||||||
MessageCallback(fn_messageCallback cb, std::shared_ptr<MessageFilter> f) : callback(cb), filter(f) {}
|
MessageCallback(fn_messageCallback cb, std::shared_ptr<MessageFilter> f)
|
||||||
MessageCallback(fn_messageCallback cb, MessageFilter f = MessageFilter()) : callback(cb), filter(std::make_shared<MessageFilter>(f)) {}
|
: callback(cb), filter(f ? f : std::make_shared<MessageFilter>()) {
|
||||||
|
if(!cb)
|
||||||
|
throw std::bad_function_call();
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageCallback(fn_messageCallback cb, MessageFilter f = MessageFilter())
|
||||||
|
: MessageCallback(cb, std::make_shared<MessageFilter>(f)) {}
|
||||||
|
|
||||||
// Allow the filter to be placed first if the user wants (maybe in the case of a lambda)
|
// Allow the filter to be placed first if the user wants (maybe in the case of a lambda)
|
||||||
MessageCallback(std::shared_ptr<MessageFilter> f, fn_messageCallback cb) : callback(cb), filter(f) {}
|
MessageCallback(std::shared_ptr<MessageFilter> f, fn_messageCallback cb)
|
||||||
MessageCallback(MessageFilter f, fn_messageCallback cb) : callback(cb), filter(std::make_shared<MessageFilter>(f)) {}
|
: MessageCallback(cb, f) {}
|
||||||
|
MessageCallback(MessageFilter f, fn_messageCallback cb)
|
||||||
|
: MessageCallback(cb, std::make_shared<MessageFilter>(f)) {}
|
||||||
|
|
||||||
virtual bool callIfMatch(const std::shared_ptr<Message>& message) const {
|
virtual bool callIfMatch(const std::shared_ptr<Message>& message) const {
|
||||||
bool ret = filter->match(message);
|
bool ret = filter->match(message);
|
||||||
|
|
@ -31,8 +39,8 @@ public:
|
||||||
const fn_messageCallback& getCallback() const { return callback; }
|
const fn_messageCallback& getCallback() const { return callback; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
fn_messageCallback callback;
|
const fn_messageCallback callback;
|
||||||
std::shared_ptr<MessageFilter> filter;
|
const std::shared_ptr<MessageFilter> filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef __CANERRORCOUNTMESSAGE_H_
|
||||||
|
#define __CANERRORCOUNTMESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
class CANErrorCountMessage : public Message {
|
||||||
|
public:
|
||||||
|
CANErrorCountMessage(uint8_t tec, uint8_t rec, bool busOffFlag)
|
||||||
|
: Message(Message::Type::CANErrorCount), transmitErrorCount(tec), receiveErrorCount(rec), busOff(busOffFlag){}
|
||||||
|
|
||||||
|
Network network;
|
||||||
|
uint8_t transmitErrorCount;
|
||||||
|
uint8_t receiveErrorCount;
|
||||||
|
bool busOff;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class CANMessage : public Message {
|
class CANMessage : public Frame {
|
||||||
public:
|
public:
|
||||||
uint32_t arbid;
|
uint32_t arbid;
|
||||||
uint8_t dlcOnWire;
|
uint8_t dlcOnWire;
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ struct MACAddress {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EthernetMessage : public Message {
|
class EthernetMessage : public Frame {
|
||||||
public:
|
public:
|
||||||
bool preemptionEnabled = false;
|
bool preemptionEnabled = false;
|
||||||
uint8_t preemptionFlags = 0;
|
uint8_t preemptionFlags = 0;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef __ETHPHYMESSAGE_H__
|
||||||
|
#define __ETHPHYMESSAGE_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/packet/ethphyregpacket.h"
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
#include "icsneo/communication/packet.h"
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4201) // nameless struct/union
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct PhyMessage {
|
||||||
|
bool Enabled;
|
||||||
|
bool WriteEnable;
|
||||||
|
bool Clause45Enable;
|
||||||
|
uint8_t version;
|
||||||
|
union {
|
||||||
|
Clause22Message clause22;
|
||||||
|
Clause45Message clause45;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Internal message which provides an interface with device ethernet PHY registers,
|
||||||
|
//with Clause22 and Clause45 message support
|
||||||
|
class EthPhyMessage : public Message {
|
||||||
|
public:
|
||||||
|
EthPhyMessage() : Message(Message::Type::EthernetPhyRegister) {}
|
||||||
|
bool appendPhyMessage(bool writeEnable, bool clause45, uint8_t phyAddrOrPort, uint8_t pageOrDevice, uint16_t regAddr, uint16_t regVal = 0x0000u, bool enabled = true);
|
||||||
|
bool appendPhyMessage(std::shared_ptr<PhyMessage> message);
|
||||||
|
size_t getMessageCount() const;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<PhyMessage>> messages;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -13,8 +13,8 @@ namespace icsneo {
|
||||||
|
|
||||||
class CANMessageFilter : public MessageFilter {
|
class CANMessageFilter : public MessageFilter {
|
||||||
public:
|
public:
|
||||||
CANMessageFilter() : MessageFilter(Network::Type::CAN), arbid(INVALID_ARBID) {}
|
CANMessageFilter() : MessageFilter(Network::Type::CAN), arbid(INVALID_ARBID) { messageType = Message::Type::Frame; }
|
||||||
CANMessageFilter(uint32_t arbid) : MessageFilter(Network::Type::CAN), arbid(arbid) {}
|
CANMessageFilter(uint32_t arbid) : MessageFilter(Network::Type::CAN), arbid(arbid) { messageType = Message::Type::Frame; }
|
||||||
|
|
||||||
bool match(const std::shared_ptr<Message>& message) const {
|
bool match(const std::shared_ptr<Message>& message) const {
|
||||||
if(!MessageFilter::match(message))
|
if(!MessageFilter::match(message))
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@ namespace icsneo {
|
||||||
|
|
||||||
class Main51MessageFilter : public MessageFilter {
|
class Main51MessageFilter : public MessageFilter {
|
||||||
public:
|
public:
|
||||||
Main51MessageFilter() : MessageFilter(Network::NetID::Main51), command(INVALID_COMMAND) {}
|
Main51MessageFilter() : MessageFilter(Message::Type::Main51), command(INVALID_COMMAND) {}
|
||||||
Main51MessageFilter(Command command) : MessageFilter(Network::NetID::Main51), command(command) {}
|
// Don't filter on Type::Main51 for Command as some Commands have their own type
|
||||||
|
// We still guarantee it's a Main51Message if it matches because of the dynamic_pointer_cast below
|
||||||
|
Main51MessageFilter(Command command) : command(command) { includeInternalInAny = true; }
|
||||||
|
|
||||||
bool match(const std::shared_ptr<Message>& message) const {
|
bool match(const std::shared_ptr<Message>& message) const override {
|
||||||
if(!MessageFilter::match(message)) {
|
if(!MessageFilter::match(message)) {
|
||||||
//std::cout << "message filter did not match base for " << message->network << std::endl;
|
//std::cout << "message filter did not match base for " << message->network << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -12,26 +12,45 @@ namespace icsneo {
|
||||||
class MessageFilter {
|
class MessageFilter {
|
||||||
public:
|
public:
|
||||||
MessageFilter() {}
|
MessageFilter() {}
|
||||||
MessageFilter(Network::Type type) : type(type) {}
|
MessageFilter(Message::Type type) : includeInternalInAny(neomessagetype_t(type) & 0x8000), messageType(type) {}
|
||||||
MessageFilter(Network::NetID netid) : type(Network::GetTypeOfNetID(netid)), netid(netid) {}
|
MessageFilter(Network::NetID netid) : MessageFilter(Network::GetTypeOfNetID(netid), netid) {}
|
||||||
virtual ~MessageFilter() {}
|
MessageFilter(Network::Type type, Network::NetID net = Network::NetID::Any) : networkType(type), netid(net) {
|
||||||
|
// If a Network::Type::Internal is used, we want to also get internal Message::Types
|
||||||
|
// The NetID we want may be in there
|
||||||
|
includeInternalInAny = (networkType == Network::Type::Internal);
|
||||||
|
}
|
||||||
|
virtual ~MessageFilter() = default;
|
||||||
// When getting "all" types of messages, include the ones marked as "internal only"
|
// When getting "all" types of messages, include the ones marked as "internal only"
|
||||||
bool includeInternalInAny = false;
|
bool includeInternalInAny = false;
|
||||||
|
|
||||||
virtual bool match(const std::shared_ptr<Message>& message) const {
|
virtual bool match(const std::shared_ptr<Message>& message) const {
|
||||||
if(!matchType(message->network.getType()))
|
if(!matchMessageType(message->type))
|
||||||
return false;
|
|
||||||
if(!matchNetID(message->network.getNetID()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if(message->type == Message::Type::Frame || message->type == Message::Type::Main51 ||
|
||||||
|
message->type == Message::Type::RawMessage || message->type == Message::Type::ReadSettings) {
|
||||||
|
RawMessage& frame = *static_cast<RawMessage*>(message.get());
|
||||||
|
if(!matchNetworkType(frame.network.getType()))
|
||||||
|
return false;
|
||||||
|
if(!matchNetID(frame.network.getNetID()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Network::Type type = Network::Type::Any;
|
Message::Type messageType = Message::Type::Invalid; // Used here for "any"
|
||||||
bool matchType(Network::Type mtype) const {
|
bool matchMessageType(Message::Type mtype) const {
|
||||||
if(type == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny))
|
if(messageType == Message::Type::Invalid && ((neomessagetype_t(mtype) & 0x8000) == 0 || includeInternalInAny))
|
||||||
return true;
|
return true;
|
||||||
return type == mtype;
|
return messageType == mtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
Network::Type networkType = Network::Type::Any;
|
||||||
|
bool matchNetworkType(Network::Type mtype) const {
|
||||||
|
if(networkType == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny))
|
||||||
|
return true;
|
||||||
|
return networkType == mtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::NetID netid = Network::NetID::Any;
|
Network::NetID netid = Network::NetID::Any;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ public:
|
||||||
uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize);
|
uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize);
|
||||||
|
|
||||||
FlexRayControlMessage(const Packet& packet);
|
FlexRayControlMessage(const Packet& packet);
|
||||||
virtual ~FlexRayControlMessage() = default;
|
|
||||||
bool decoded = false;
|
bool decoded = false;
|
||||||
uint8_t controller = 0xff; // Controller index, either 0 or 1
|
uint8_t controller = 0xff; // Controller index, either 0 or 1
|
||||||
FlexRay::Opcode opcode = FlexRay::Opcode::Unknown;
|
FlexRay::Opcode opcode = FlexRay::Opcode::Unknown;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class FlexRayMessage : public Message {
|
class FlexRayMessage : public Frame {
|
||||||
public:
|
public:
|
||||||
uint16_t slotid = 0;
|
uint16_t slotid = 0;
|
||||||
double tsslen = 0;
|
double tsslen = 0;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class ISO9141Message : public Message {
|
class ISO9141Message : public Frame {
|
||||||
public:
|
public:
|
||||||
std::array<uint8_t, 3> header;
|
std::array<uint8_t, 3> header;
|
||||||
bool isInit = false;
|
bool isInit = false;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef __LOGICALDISKINFOMESSAGE_H_
|
||||||
|
#define __LOGICALDISKINFOMESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
class LogicalDiskInfoMessage : public Message {
|
||||||
|
public:
|
||||||
|
LogicalDiskInfoMessage(bool isConnected, uint32_t numSectors, uint32_t numHidden, uint32_t sectorSize) :
|
||||||
|
Message(Message::Type::LogicalDiskInfo), connected(isConnected), sectors(numSectors),
|
||||||
|
hiddenSectors(numHidden), bytesPerSector(sectorSize) {}
|
||||||
|
|
||||||
|
const bool connected;
|
||||||
|
const uint32_t sectors;
|
||||||
|
const uint32_t hiddenSectors;
|
||||||
|
const uint32_t bytesPerSector;
|
||||||
|
|
||||||
|
uint64_t getReportedSize() const { return uint64_t(sectors) * bytesPerSector; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class Main51Message : public Message {
|
class Main51Message : public RawMessage {
|
||||||
public:
|
public:
|
||||||
virtual ~Main51Message() = default;
|
Main51Message() : RawMessage(Message::Type::Main51, Network::NetID::Main51) {}
|
||||||
Command command = Command(0);
|
Command command = Command(0);
|
||||||
bool forceShortFormat = false; // Necessary for EnableNetworkCom and EnableNetworkComEx
|
bool forceShortFormat = false; // Necessary for EnableNetworkCom and EnableNetworkComEx
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#ifndef __MESSAGE_H_
|
#ifndef __MESSAGE_H_
|
||||||
#define __MESSAGE_H_
|
#define __MESSAGE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef uint16_t neomessagetype_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
#include "icsneo/communication/network.h"
|
#include "icsneo/communication/network.h"
|
||||||
|
|
@ -10,10 +13,44 @@ namespace icsneo {
|
||||||
|
|
||||||
class Message {
|
class Message {
|
||||||
public:
|
public:
|
||||||
|
enum class Type : neomessagetype_t {
|
||||||
|
Frame = 0,
|
||||||
|
|
||||||
|
CANErrorCount = 0x100,
|
||||||
|
|
||||||
|
// Past 0x8000 are all for internal use only
|
||||||
|
Invalid = 0x8000,
|
||||||
|
RawMessage = 0x8001,
|
||||||
|
ReadSettings = 0x8002,
|
||||||
|
ResetStatus = 0x8003,
|
||||||
|
DeviceVersion = 0x8004,
|
||||||
|
Main51 = 0x8005,
|
||||||
|
FlexRayControl = 0x8006,
|
||||||
|
EthernetPhyRegister = 0x8007,
|
||||||
|
LogicalDiskInfo = 0x8008,
|
||||||
|
};
|
||||||
|
|
||||||
|
Message(Type t) : type(t) {}
|
||||||
virtual ~Message() = default;
|
virtual ~Message() = default;
|
||||||
|
const Type type;
|
||||||
|
uint64_t timestamp = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RawMessage : public Message {
|
||||||
|
public:
|
||||||
|
RawMessage(Message::Type type = Message::Type::RawMessage) : Message(type) {}
|
||||||
|
RawMessage(Message::Type type, Network net) : Message(type), network(net) {}
|
||||||
|
RawMessage(Network net) : Message(Message::Type::RawMessage), network(net) {}
|
||||||
|
RawMessage(Network net, std::vector<uint8_t> d) : Message(Message::Type::RawMessage), network(net), data(d) {}
|
||||||
|
|
||||||
Network network;
|
Network network;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
uint64_t timestamp = 0;
|
};
|
||||||
|
|
||||||
|
class Frame : public RawMessage {
|
||||||
|
public:
|
||||||
|
Frame() : RawMessage(Message::Type::Frame) {}
|
||||||
|
|
||||||
uint16_t description = 0;
|
uint16_t description = 0;
|
||||||
bool transmitted = false;
|
bool transmitted = false;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
@ -23,4 +60,18 @@ public:
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#ifdef __ICSNEOC_H_
|
||||||
|
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_FRAME (0x0)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT (0x100)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_INVALID (0x8000)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_RAW_MESSAGE (0x8001)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_READ_SETTINGS (0x8002)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_RESET_STATUS (0x8003)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_DEVICE_VERSION (0x8004)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_MAIN51 (0x8005)
|
||||||
|
#define ICSNEO_MESSAGE_TYPE_FLEXRAY_CONTROL (0x8006)
|
||||||
|
|
||||||
|
#endif // __ICSNEOC_H_
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "icsneo/communication/network.h"
|
#include "icsneo/communication/network.h"
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
|
@ -18,12 +19,12 @@ typedef union {
|
||||||
uint32_t extendedFrame : 1;
|
uint32_t extendedFrame : 1;
|
||||||
uint32_t remoteFrame : 1;
|
uint32_t remoteFrame : 1;
|
||||||
uint32_t crcError : 1;
|
uint32_t crcError : 1;
|
||||||
uint32_t canErrorPassive : 1;
|
uint32_t canErrorPassive : 1; // Occupies the same space as headerCRCError
|
||||||
uint32_t incompleteFrame : 1;
|
uint32_t incompleteFrame : 1;
|
||||||
uint32_t lostArbitration : 1;
|
uint32_t lostArbitration : 1;
|
||||||
uint32_t undefinedError : 1;
|
uint32_t undefinedError : 1;
|
||||||
uint32_t canBusOff : 1;
|
uint32_t canBusOff : 1;
|
||||||
uint32_t canErrorWarning : 1;
|
uint32_t canBusRecovered : 1;
|
||||||
uint32_t canBusShortedPlus : 1;
|
uint32_t canBusShortedPlus : 1;
|
||||||
uint32_t canBusShortedGround : 1;
|
uint32_t canBusShortedGround : 1;
|
||||||
uint32_t checksumError : 1;
|
uint32_t checksumError : 1;
|
||||||
|
|
@ -101,24 +102,34 @@ typedef union {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
neomessage_statusbitfield_t status;
|
uint8_t _reserved1[16];
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
uint64_t timestampReserved;
|
uint64_t _reservedTimestamp;
|
||||||
const uint8_t* data;
|
uint8_t _reserved2[sizeof(size_t) * 2 + 7 + sizeof(neonetid_t) + sizeof(neonettype_t)];
|
||||||
size_t length;
|
neomessagetype_t messageType;
|
||||||
uint8_t header[4];
|
uint8_t _reserved3[12];
|
||||||
neonetid_t netid;
|
|
||||||
neonettype_t type;
|
|
||||||
uint8_t reserved0;
|
|
||||||
uint16_t description;
|
|
||||||
uint8_t reserved1[14];
|
|
||||||
} neomessage_t; // 72 bytes total
|
} neomessage_t; // 72 bytes total
|
||||||
// Any time you add another neomessage_*_t type, make sure to add it to the static_asserts below!
|
// Any time you add another neomessage_*_t type, make sure to add it to the static_asserts below!
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
neomessage_statusbitfield_t status;
|
neomessage_statusbitfield_t status;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
uint64_t timestampReserved;
|
uint64_t _reservedTimestamp;
|
||||||
|
const uint8_t* data;
|
||||||
|
size_t length;
|
||||||
|
uint8_t header[4];
|
||||||
|
neonetid_t netid;
|
||||||
|
neonettype_t type;
|
||||||
|
uint8_t _reserved0;
|
||||||
|
uint16_t description;
|
||||||
|
neomessagetype_t messageType;
|
||||||
|
uint8_t _reserved1[12];
|
||||||
|
} neomessage_frame_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
neomessage_statusbitfield_t status;
|
||||||
|
uint64_t timestamp;
|
||||||
|
uint64_t _reservedTimestamp;
|
||||||
const uint8_t* data;
|
const uint8_t* data;
|
||||||
size_t length;
|
size_t length;
|
||||||
uint32_t arbid;
|
uint32_t arbid;
|
||||||
|
|
@ -126,22 +137,38 @@ typedef struct {
|
||||||
neonettype_t type;
|
neonettype_t type;
|
||||||
uint8_t dlcOnWire;
|
uint8_t dlcOnWire;
|
||||||
uint16_t description;
|
uint16_t description;
|
||||||
uint8_t reserved[14];
|
neomessagetype_t messageType;
|
||||||
|
uint8_t _reserved1[12];
|
||||||
} neomessage_can_t;
|
} neomessage_can_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
neomessage_statusbitfield_t status;
|
neomessage_statusbitfield_t status;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
uint64_t timestampReserved;
|
uint64_t _reservedTimestamp;
|
||||||
|
size_t _reserved2[2];
|
||||||
|
uint8_t transmitErrorCount;
|
||||||
|
uint8_t receiveErrorCount;
|
||||||
|
uint8_t _reserved3[5];
|
||||||
|
neonetid_t netid;
|
||||||
|
neonettype_t type;
|
||||||
|
neomessagetype_t messageType;
|
||||||
|
uint8_t _reserved4[12];
|
||||||
|
} neomessage_can_error_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
neomessage_statusbitfield_t status;
|
||||||
|
uint64_t timestamp;
|
||||||
|
uint64_t _reservedTimestamp;
|
||||||
const uint8_t* data;
|
const uint8_t* data;
|
||||||
size_t length;
|
size_t length;
|
||||||
uint8_t preemptionFlags;
|
uint8_t preemptionFlags;
|
||||||
uint8_t reservedHeader[3];
|
uint8_t _reservedHeader[3];
|
||||||
neonetid_t netid;
|
neonetid_t netid;
|
||||||
neonettype_t type;
|
neonettype_t type;
|
||||||
uint8_t reserved0;
|
uint8_t _reserved0;
|
||||||
uint16_t description;
|
uint16_t description;
|
||||||
uint8_t reserved1[14];
|
neomessagetype_t messageType;
|
||||||
|
uint8_t _reserved1[12];
|
||||||
} neomessage_eth_t;
|
} neomessage_eth_t;
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
@ -151,7 +178,9 @@ typedef struct {
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
static_assert(sizeof(neomessage_t) == (56 + sizeof(void*) + sizeof(size_t)), "neomessage_t size is incorrect! Changing size will break compatibility with existing C API programs.");
|
static_assert(sizeof(neomessage_t) == (56 + sizeof(void*) + sizeof(size_t)), "neomessage_t size is incorrect! Changing size will break compatibility with existing C API programs.");
|
||||||
|
static_assert(sizeof(neomessage_frame_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Base frame is not)");
|
||||||
static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN is not)");
|
static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN is not)");
|
||||||
|
static_assert(sizeof(neomessage_can_error_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN error is not)");
|
||||||
static_assert(sizeof(neomessage_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)");
|
static_assert(sizeof(neomessage_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)");
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef __READMEMORYMESSAGE_H_
|
||||||
|
#define __READMEMORYMESSAGE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/message.h"
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
class NeoReadMemorySDMessage : public RawMessage {
|
||||||
|
public:
|
||||||
|
NeoReadMemorySDMessage() : RawMessage(Message::Type::RawMessage, Network::NetID::NeoMemorySDRead) {}
|
||||||
|
uint32_t startAddress = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class ReadSettingsMessage : public Message {
|
class ReadSettingsMessage : public RawMessage {
|
||||||
public:
|
public:
|
||||||
virtual ~ReadSettingsMessage() = default;
|
ReadSettingsMessage() : RawMessage(Message::Type::ReadSettings, Network::NetID::ReadSettings) {}
|
||||||
|
|
||||||
enum class Response : uint8_t {
|
enum class Response : uint8_t {
|
||||||
OK = 0,
|
OK = 0,
|
||||||
|
|
@ -19,7 +19,8 @@ public:
|
||||||
InvalidSubversion = 3,
|
InvalidSubversion = 3,
|
||||||
NotEnoughMemory = 4,
|
NotEnoughMemory = 4,
|
||||||
APIFailure = 5,
|
APIFailure = 5,
|
||||||
APIUnsupported = 6
|
APIUnsupported = 6,
|
||||||
|
OKDefaultsUsed = 7, // Got the settings okay, but the defaults were used (after firmware upgrade or a checksum error)
|
||||||
};
|
};
|
||||||
|
|
||||||
Response response;
|
Response response;
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,15 @@
|
||||||
|
|
||||||
#include "icsneo/communication/message/main51message.h"
|
#include "icsneo/communication/message/main51message.h"
|
||||||
#include "icsneo/communication/command.h"
|
#include "icsneo/communication/command.h"
|
||||||
|
#include "icsneo/platform/optional.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class ResetStatusMessage : public Message {
|
class ResetStatusMessage : public Message {
|
||||||
public:
|
public:
|
||||||
ResetStatusMessage() : Message() {}
|
ResetStatusMessage() : Message(Message::Type::ResetStatus) {}
|
||||||
virtual ~ResetStatusMessage() = default;
|
|
||||||
uint16_t mainLoopTime;
|
uint16_t mainLoopTime;
|
||||||
uint16_t maxMainLoopTime;
|
uint16_t maxMainLoopTime;
|
||||||
bool justReset;
|
bool justReset;
|
||||||
|
|
@ -28,8 +29,8 @@ public:
|
||||||
bool cmTooBig;
|
bool cmTooBig;
|
||||||
bool hidUsbState;
|
bool hidUsbState;
|
||||||
bool fpgaUsbState;
|
bool fpgaUsbState;
|
||||||
uint16_t busVoltage;
|
icsneo::optional<uint16_t> busVoltage;
|
||||||
uint16_t deviceTemperature;
|
icsneo::optional<uint16_t> deviceTemperature;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,18 @@ namespace icsneo {
|
||||||
|
|
||||||
class VersionMessage : public Message {
|
class VersionMessage : public Message {
|
||||||
public:
|
public:
|
||||||
VersionMessage(bool main) : MainChip(main) { network = Network::NetID::Main51; }
|
enum Chip : uint8_t {
|
||||||
|
MainChip,
|
||||||
|
SecondaryChips
|
||||||
|
};
|
||||||
|
|
||||||
// If true, the included version is for the main chip
|
VersionMessage(Chip chip) : Message(Message::Type::DeviceVersion), ForChip(chip) {}
|
||||||
const bool MainChip;
|
|
||||||
|
|
||||||
// nullopt here indicates invalid
|
// nullopt here indicates invalid
|
||||||
std::vector< optional<DeviceAppVersion> > Versions;
|
std::vector< optional<DeviceAppVersion> > Versions;
|
||||||
|
|
||||||
|
// What chips the versions are for
|
||||||
|
const Chip ForChip;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,6 @@ public:
|
||||||
void joinThreads() override;
|
void joinThreads() override;
|
||||||
bool sendPacket(std::vector<uint8_t>& bytes) override;
|
bool sendPacket(std::vector<uint8_t>& bytes) override;
|
||||||
|
|
||||||
protected:
|
|
||||||
bool preprocessPacket(std::deque<uint8_t>& usbReadFifo);
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum class CommandType : uint8_t {
|
enum class CommandType : uint8_t {
|
||||||
PlasmaReadRequest = 0x10, // Status read request to HSC
|
PlasmaReadRequest = 0x10, // Status read request to HSC
|
||||||
PlasmaStatusResponse = 0x11, // Status response by HSC
|
PlasmaStatusResponse = 0x11, // Status response by HSC
|
||||||
|
|
@ -49,6 +45,10 @@ private:
|
||||||
Microblaze_to_HostPC = 0x81 // Microblaze processor data to host PC
|
Microblaze_to_HostPC = 0x81 // Microblaze processor data to host PC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool preprocessPacket(std::deque<uint8_t>& usbReadFifo);
|
||||||
|
|
||||||
|
private:
|
||||||
static bool CommandTypeIsValid(CommandType cmd) {
|
static bool CommandTypeIsValid(CommandType cmd) {
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case CommandType::PlasmaReadRequest:
|
case CommandType::PlasmaReadRequest:
|
||||||
|
|
@ -77,8 +77,10 @@ private:
|
||||||
static bool CommandTypeHasAddress(CommandType cmd) {
|
static bool CommandTypeHasAddress(CommandType cmd) {
|
||||||
// Check CommandTypeIsValid before this, you will get false on an invalid command
|
// Check CommandTypeIsValid before this, you will get false on an invalid command
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case CommandType::SDCC1_to_HostPC:
|
case CommandType::HostPC_to_SDCC1:
|
||||||
case CommandType::SDCC2_to_HostPC:
|
case CommandType::HostPC_from_SDCC1:
|
||||||
|
case CommandType::HostPC_to_SDCC2:
|
||||||
|
case CommandType::HostPC_from_SDCC2:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,9 @@ public:
|
||||||
RED_EXT_MEMORYREAD = 20,
|
RED_EXT_MEMORYREAD = 20,
|
||||||
RED_INT_MEMORYREAD = 21,
|
RED_INT_MEMORYREAD = 21,
|
||||||
RED_DFLASH_READ = 22,
|
RED_DFLASH_READ = 22,
|
||||||
RED_SDCARD_READ = 23,
|
NeoMemorySDRead = 23, // Response from NeoMemory (MemoryTypeSD)
|
||||||
CAN_ERRBITS = 24,
|
CAN_ERRBITS = 24,
|
||||||
RED_DFLASH_WRITE_DONE = 25,
|
NeoMemoryWriteDone = 25,
|
||||||
RED_WAVE_CAN1_LOGICAL = 26,
|
RED_WAVE_CAN1_LOGICAL = 26,
|
||||||
RED_WAVE_CAN2_LOGICAL = 27,
|
RED_WAVE_CAN2_LOGICAL = 27,
|
||||||
RED_WAVE_LIN1_LOGICAL = 28,
|
RED_WAVE_LIN1_LOGICAL = 28,
|
||||||
|
|
@ -117,6 +117,8 @@ public:
|
||||||
HSCAN7 = 97,
|
HSCAN7 = 97,
|
||||||
LIN6 = 98,
|
LIN6 = 98,
|
||||||
LSFTCAN2 = 99,
|
LSFTCAN2 = 99,
|
||||||
|
LogicalDiskInfo = 187,
|
||||||
|
EthPHYControl = 239,
|
||||||
FlexRayControl = 243,
|
FlexRayControl = 243,
|
||||||
HW_COM_Latency_Test = 512,
|
HW_COM_Latency_Test = 512,
|
||||||
DeviceStatus = 513,
|
DeviceStatus = 513,
|
||||||
|
|
@ -270,6 +272,10 @@ public:
|
||||||
case NetID::FlexRayControl:
|
case NetID::FlexRayControl:
|
||||||
case NetID::Main51:
|
case NetID::Main51:
|
||||||
case NetID::ReadSettings:
|
case NetID::ReadSettings:
|
||||||
|
case NetID::LogicalDiskInfo:
|
||||||
|
case NetID::EthPHYControl:
|
||||||
|
case NetID::NeoMemorySDRead:
|
||||||
|
case NetID::NeoMemoryWriteDone:
|
||||||
return Type::Internal;
|
return Type::Internal;
|
||||||
case NetID::Invalid:
|
case NetID::Invalid:
|
||||||
case NetID::Any:
|
case NetID::Any:
|
||||||
|
|
@ -358,12 +364,12 @@ public:
|
||||||
return "RED_INT_MEMORYREAD";
|
return "RED_INT_MEMORYREAD";
|
||||||
case NetID::RED_DFLASH_READ:
|
case NetID::RED_DFLASH_READ:
|
||||||
return "RED_DFLASH_READ";
|
return "RED_DFLASH_READ";
|
||||||
case NetID::RED_SDCARD_READ:
|
case NetID::NeoMemorySDRead:
|
||||||
return "RED_SDCARD_READ";
|
return "NeoMemorySDRead";
|
||||||
case NetID::CAN_ERRBITS:
|
case NetID::CAN_ERRBITS:
|
||||||
return "CAN_ERRBITS";
|
return "CAN_ERRBITS";
|
||||||
case NetID::RED_DFLASH_WRITE_DONE:
|
case NetID::NeoMemoryWriteDone:
|
||||||
return "RED_DFLASH_WRITE_DONE";
|
return "NeoMemoryWriteDone";
|
||||||
case NetID::RED_WAVE_CAN1_LOGICAL:
|
case NetID::RED_WAVE_CAN1_LOGICAL:
|
||||||
return "RED_WAVE_CAN1_LOGICAL";
|
return "RED_WAVE_CAN1_LOGICAL";
|
||||||
case NetID::RED_WAVE_CAN2_LOGICAL:
|
case NetID::RED_WAVE_CAN2_LOGICAL:
|
||||||
|
|
@ -504,6 +510,10 @@ public:
|
||||||
return "LIN 6";
|
return "LIN 6";
|
||||||
case NetID::LSFTCAN2:
|
case NetID::LSFTCAN2:
|
||||||
return "LSFTCAN 2";
|
return "LSFTCAN 2";
|
||||||
|
case NetID::LogicalDiskInfo:
|
||||||
|
return "Logical Disk Information";
|
||||||
|
case NetID::EthPHYControl:
|
||||||
|
return "Ethernet PHY Register Control";
|
||||||
case NetID::FlexRayControl:
|
case NetID::FlexRayControl:
|
||||||
return "FlexRay Control";
|
return "FlexRay Control";
|
||||||
case NetID::HW_COM_Latency_Test:
|
case NetID::HW_COM_Latency_Test:
|
||||||
|
|
@ -826,9 +836,9 @@ private:
|
||||||
#define ICSNEO_NETID_RED_EXT_MEMORYREAD 20
|
#define ICSNEO_NETID_RED_EXT_MEMORYREAD 20
|
||||||
#define ICSNEO_NETID_RED_INT_MEMORYREAD 21
|
#define ICSNEO_NETID_RED_INT_MEMORYREAD 21
|
||||||
#define ICSNEO_NETID_RED_DFLASH_READ 22
|
#define ICSNEO_NETID_RED_DFLASH_READ 22
|
||||||
#define ICSNEO_NETID_RED_SDCARD_READ 23
|
#define ICSNEO_NETID_NEOMEMORY_SD_READ 23
|
||||||
#define ICSNEO_NETID_CAN_ERRBITS 24
|
#define ICSNEO_NETID_CAN_ERRBITS 24
|
||||||
#define ICSNEO_NETID_RED_DFLASH_WRITE_DONE 25
|
#define ICSNEO_NETID_NEOMEMORY_WRITE_DONE 25
|
||||||
#define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL 26
|
#define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL 26
|
||||||
#define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL 27
|
#define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL 27
|
||||||
#define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL 28
|
#define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL 28
|
||||||
|
|
@ -902,6 +912,8 @@ private:
|
||||||
#define ICSNEO_NETID_HSCAN7 97
|
#define ICSNEO_NETID_HSCAN7 97
|
||||||
#define ICSNEO_NETID_LIN6 98
|
#define ICSNEO_NETID_LIN6 98
|
||||||
#define ICSNEO_NETID_LSFTCAN2 99
|
#define ICSNEO_NETID_LSFTCAN2 99
|
||||||
|
#define ICSNEO_NETID_LOGICAL_DISK_INFO 187
|
||||||
|
#define ICSNEO_NETID_ETH_PHY_CONTROL 239
|
||||||
#define ICSNEO_NETID_FLEXRAY_CONTROL 243
|
#define ICSNEO_NETID_FLEXRAY_CONTROL 243
|
||||||
#define ICSNEO_NETID_HW_COM_LATENCY_TEST 512
|
#define ICSNEO_NETID_HW_COM_LATENCY_TEST 512
|
||||||
#define ICSNEO_NETID_DEVICE_STATUS 513
|
#define ICSNEO_NETID_DEVICE_STATUS 513
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace icsneo {
|
||||||
typedef uint16_t icscm_bitfield;
|
typedef uint16_t icscm_bitfield;
|
||||||
|
|
||||||
struct HardwareCANPacket {
|
struct HardwareCANPacket {
|
||||||
static std::shared_ptr<CANMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||||
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
|
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef __ETHPHYREGPACKET_H__
|
||||||
|
#define __ETHPHYREGPACKET_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace icsneo
|
||||||
|
{
|
||||||
|
|
||||||
|
class Packetizer;
|
||||||
|
class EthPhyMessage;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4201) // nameless struct/union
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct PhyRegisterHeader_t {
|
||||||
|
uint16_t numEntries;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t entryBytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Clause22Message {
|
||||||
|
uint8_t phyAddr; //5 bits
|
||||||
|
uint8_t page; //8 bits
|
||||||
|
uint16_t regAddr; //5 bits
|
||||||
|
uint16_t regVal;
|
||||||
|
}; //6 bytes
|
||||||
|
|
||||||
|
struct Clause45Message {
|
||||||
|
uint8_t port; //5 bits
|
||||||
|
uint8_t device; //5 bits
|
||||||
|
uint16_t regAddr;
|
||||||
|
uint16_t regVal;
|
||||||
|
}; //6 bytes
|
||||||
|
|
||||||
|
struct PhyRegisterPacket_t {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t Enabled : 1;
|
||||||
|
uint16_t WriteEnable : 1;
|
||||||
|
uint16_t Clause45Enable : 1;
|
||||||
|
uint16_t reserved : 9;
|
||||||
|
uint16_t version : 4;
|
||||||
|
};
|
||||||
|
uint16_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
Clause22Message clause22;
|
||||||
|
Clause45Message clause45;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static constexpr size_t MaxPhyEntries = 128u;
|
||||||
|
static constexpr size_t MaxBytesPhyEntries = MaxPhyEntries * sizeof(PhyRegisterHeader_t);
|
||||||
|
static constexpr uint8_t PhyPacketVersion = 1u;
|
||||||
|
static constexpr uint8_t FiveBits = 0x1Fu;
|
||||||
|
|
||||||
|
class EthPhyMessage;
|
||||||
|
|
||||||
|
struct HardwareEthernetPhyRegisterPacket {
|
||||||
|
static std::shared_ptr<EthPhyMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
|
||||||
|
static bool EncodeFromMessage(const EthPhyMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //__cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef __LOGICALDISKINFOPACKET_H__
|
||||||
|
#define __LOGICALDISKINFOPACKET_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#include "icsneo/communication/message/logicaldiskinfomessage.h"
|
||||||
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
#pragma pack(push,2)
|
||||||
|
struct LogicalDiskInfoPacket {
|
||||||
|
static std::shared_ptr<LogicalDiskInfoMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||||
|
|
||||||
|
uint16_t isConnected;
|
||||||
|
uint32_t numSectors;
|
||||||
|
uint32_t hiddenSectors;
|
||||||
|
uint32_t bytesPerSector;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -23,7 +23,7 @@ public:
|
||||||
std::vector<std::shared_ptr<Packet>> output();
|
std::vector<std::shared_ptr<Packet>> output();
|
||||||
|
|
||||||
bool disableChecksum = false; // Even for short packets
|
bool disableChecksum = false; // Even for short packets
|
||||||
bool align16bit = true; // Not needed for Gigalog, Galaxy, etc and newer
|
bool align16bit = true; // Not needed for Mars, Galaxy, etc and newer
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class ReadState {
|
enum class ReadState {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cstdint>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "icsneo/api/eventmanager.h"
|
#include "icsneo/api/eventmanager.h"
|
||||||
|
|
@ -16,6 +17,10 @@
|
||||||
#include "icsneo/device/nullsettings.h"
|
#include "icsneo/device/nullsettings.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/device/deviceversion.h"
|
#include "icsneo/device/deviceversion.h"
|
||||||
|
#include "icsneo/device/founddevice.h"
|
||||||
|
#include "icsneo/disk/diskreaddriver.h"
|
||||||
|
#include "icsneo/disk/diskwritedriver.h"
|
||||||
|
#include "icsneo/disk/nulldiskdriver.h"
|
||||||
#include "icsneo/communication/communication.h"
|
#include "icsneo/communication/communication.h"
|
||||||
#include "icsneo/communication/packetizer.h"
|
#include "icsneo/communication/packetizer.h"
|
||||||
#include "icsneo/communication/encoder.h"
|
#include "icsneo/communication/encoder.h"
|
||||||
|
|
@ -24,10 +29,25 @@
|
||||||
#include "icsneo/communication/message/resetstatusmessage.h"
|
#include "icsneo/communication/message/resetstatusmessage.h"
|
||||||
#include "icsneo/device/extensions/flexray/controller.h"
|
#include "icsneo/device/extensions/flexray/controller.h"
|
||||||
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
|
||||||
|
#include "icsneo/communication/message/ethphymessage.h"
|
||||||
#include "icsneo/third-party/concurrentqueue/concurrentqueue.h"
|
#include "icsneo/third-party/concurrentqueue/concurrentqueue.h"
|
||||||
#include "icsneo/platform/optional.h"
|
#include "icsneo/platform/optional.h"
|
||||||
#include "icsneo/platform/nodiscard.h"
|
#include "icsneo/platform/nodiscard.h"
|
||||||
|
|
||||||
|
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
|
||||||
|
static constexpr DeviceType::Enum DEVICE_TYPE = type; \
|
||||||
|
className(const FoundDevice& dev) : className(neodevice_t(dev, DEVICE_TYPE), dev.makeDriver) {}
|
||||||
|
|
||||||
|
// Devices which are discernable by the first two characters of their serial
|
||||||
|
#define ICSNEO_FINDABLE_DEVICE(className, type, serialStart) \
|
||||||
|
static constexpr const char* SERIAL_START = serialStart; \
|
||||||
|
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
|
||||||
|
|
||||||
|
// Devices which are discernable by their USB PID
|
||||||
|
#define ICSNEO_FINDABLE_DEVICE_BY_PID(className, type, pid) \
|
||||||
|
static constexpr const uint16_t PRODUCT_ID = pid; \
|
||||||
|
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class DeviceExtension;
|
class DeviceExtension;
|
||||||
|
|
@ -42,7 +62,6 @@ public:
|
||||||
|
|
||||||
uint16_t getTimestampResolution() const;
|
uint16_t getTimestampResolution() const;
|
||||||
DeviceType getType() const { return DeviceType(data.type); }
|
DeviceType getType() const { return DeviceType(data.type); }
|
||||||
uint16_t getProductId() const { return productId; }
|
|
||||||
std::string getSerial() const { return data.serial; }
|
std::string getSerial() const { return data.serial; }
|
||||||
uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); }
|
uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); }
|
||||||
const neodevice_t& getNeoDevice() const { return data; }
|
const neodevice_t& getNeoDevice() const { return data; }
|
||||||
|
|
@ -121,8 +140,8 @@ public:
|
||||||
int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); }
|
int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); }
|
||||||
bool removeMessageCallback(int id) { return com->removeMessageCallback(id); }
|
bool removeMessageCallback(int id) { return com->removeMessageCallback(id); }
|
||||||
|
|
||||||
bool transmit(std::shared_ptr<Message> message);
|
bool transmit(std::shared_ptr<Frame> frame);
|
||||||
bool transmit(std::vector<std::shared_ptr<Message>> messages);
|
bool transmit(std::vector<std::shared_ptr<Frame>> frames);
|
||||||
|
|
||||||
void setWriteBlocks(bool blocks);
|
void setWriteBlocks(bool blocks);
|
||||||
|
|
||||||
|
|
@ -138,6 +157,74 @@ public:
|
||||||
virtual size_t getNetworkCountByType(Network::Type) const;
|
virtual size_t getNetworkCountByType(Network::Type) const;
|
||||||
virtual Network getNetworkByNumber(Network::Type, size_t) const;
|
virtual Network getNetworkByNumber(Network::Type, size_t) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from the logical disk in this device, starting from byte `pos`
|
||||||
|
* and reading up to `amount` bytes.
|
||||||
|
*
|
||||||
|
* The number of bytes read will be returned in case of success.
|
||||||
|
*
|
||||||
|
* If the number of bytes read is less than the amount requested,
|
||||||
|
* an error will be set in icsneo::GetLastError() explaining why.
|
||||||
|
* Likely, either the end of the logical disk has been reached, or
|
||||||
|
* the timeout was reached while the read had only partially completed.
|
||||||
|
*
|
||||||
|
* Upon failure, icsneo::nullopt will be returned and an error will be
|
||||||
|
* set in icsneo::GetLastError().
|
||||||
|
*/
|
||||||
|
optional<uint64_t> readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount,
|
||||||
|
std::chrono::milliseconds timeout = Disk::DefaultTimeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to the logical disk in this device, starting from byte `pos`
|
||||||
|
* and writing up to `amount` bytes.
|
||||||
|
*
|
||||||
|
* The number of bytes written will be returned in case of success.
|
||||||
|
*
|
||||||
|
* If the number of bytes written is less than the amount requested,
|
||||||
|
* an error will be set in icsneo::GetLastError() explaining why.
|
||||||
|
* Likely, either the end of the logical disk has been reached, or
|
||||||
|
* the timeout was reached while the write had only partially completed.
|
||||||
|
*
|
||||||
|
* Upon failure, icsneo::nullopt will be returned and an error will be
|
||||||
|
* set in icsneo::GetLastError().
|
||||||
|
*/
|
||||||
|
optional<uint64_t> writeLogicalDisk(uint64_t pos, const uint8_t* from, uint64_t amount,
|
||||||
|
std::chrono::milliseconds timeout = Disk::DefaultTimeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the logical disk is connected. This means the disk is inserted,
|
||||||
|
* and if required (for instance for multi-card configurations), configured
|
||||||
|
* properly.
|
||||||
|
*
|
||||||
|
* This method is synchronous and contacts the device for the latest status.
|
||||||
|
*
|
||||||
|
* `icsneo::nullopt` will be returned if the device does not respond in a
|
||||||
|
* timely manner.
|
||||||
|
*/
|
||||||
|
optional<bool> isLogicalDiskConnected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the connected logical disk in bytes.
|
||||||
|
*
|
||||||
|
* This method is synchronous and contacts the device for the latest status.
|
||||||
|
*
|
||||||
|
* `icsneo::nullopt` will be returned if the device does not respond in a
|
||||||
|
* timely manner, or if the disk is disconnected/improperly configured.
|
||||||
|
*/
|
||||||
|
optional<uint64_t> getLogicalDiskSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the offset to the VSA filesystem within the logical disk, represented
|
||||||
|
* in bytes.
|
||||||
|
*
|
||||||
|
* This method is synchronous and consacts the device for the latest status
|
||||||
|
* if necessary.
|
||||||
|
*
|
||||||
|
* `icsneo::nullopt` will be returned if the device does not respond in a
|
||||||
|
* timely manner, or if the disk is disconnected/improperly configured.
|
||||||
|
*/
|
||||||
|
optional<uint64_t> getVSAOffsetInLogicalDisk();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the number of Ethernet (DoIP) Activation lines present
|
* Retrieve the number of Ethernet (DoIP) Activation lines present
|
||||||
* on this device.
|
* on this device.
|
||||||
|
|
@ -224,11 +311,18 @@ public:
|
||||||
|
|
||||||
const device_eventhandler_t& getEventHandler() const { return report; }
|
const device_eventhandler_t& getEventHandler() const { return report; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell whether the current device supports reading and writing
|
||||||
|
* Ethernet PHY registers through MDIO.
|
||||||
|
*/
|
||||||
|
virtual bool getEthPhyRegControlSupported() const { return false; }
|
||||||
|
|
||||||
|
optional<EthPhyMessage> sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||||
|
|
||||||
std::shared_ptr<Communication> com;
|
std::shared_ptr<Communication> com;
|
||||||
std::unique_ptr<IDeviceSettings> settings;
|
std::unique_ptr<IDeviceSettings> settings;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint16_t productId = 0;
|
|
||||||
bool online = false;
|
bool online = false;
|
||||||
int messagePollingCallbackID = 0;
|
int messagePollingCallbackID = 0;
|
||||||
int internalHandlerCallbackID = 0;
|
int internalHandlerCallbackID = 0;
|
||||||
|
|
@ -243,24 +337,28 @@ protected:
|
||||||
std::array<optional<double>, 2> miscAnalog;
|
std::array<optional<double>, 2> miscAnalog;
|
||||||
|
|
||||||
// START Initialization Functions
|
// START Initialization Functions
|
||||||
Device(neodevice_t neodevice = { 0 }) {
|
Device(neodevice_t neodevice) : data(neodevice) {
|
||||||
data = neodevice;
|
|
||||||
data.device = this;
|
data.device = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Driver, typename Settings = NullSettings>
|
template<typename Settings = NullSettings, typename DiskRead = Disk::NullDriver, typename DiskWrite = Disk::NullDriver>
|
||||||
void initialize() {
|
void initialize(const driver_factory_t& makeDriver) {
|
||||||
report = makeEventHandler();
|
report = makeEventHandler();
|
||||||
auto driver = makeDriver<Driver>();
|
|
||||||
setupDriver(*driver);
|
|
||||||
auto encoder = makeEncoder();
|
auto encoder = makeEncoder();
|
||||||
setupEncoder(*encoder);
|
setupEncoder(*encoder);
|
||||||
auto decoder = makeDecoder();
|
auto decoder = makeDecoder();
|
||||||
setupDecoder(*decoder);
|
setupDecoder(*decoder);
|
||||||
com = makeCommunication(std::move(driver), std::bind(&Device::makeConfiguredPacketizer, this), std::move(encoder), std::move(decoder));
|
com = makeCommunication(
|
||||||
|
makeDriver(report, getWritableNeoDevice()),
|
||||||
|
std::bind(&Device::makeConfiguredPacketizer, this),
|
||||||
|
std::move(encoder),
|
||||||
|
std::move(decoder)
|
||||||
|
);
|
||||||
setupCommunication(*com);
|
setupCommunication(*com);
|
||||||
settings = makeSettings<Settings>(com);
|
settings = makeSettings<Settings>(com);
|
||||||
setupSettings(*settings);
|
setupSettings(*settings);
|
||||||
|
diskReadDriver = std::unique_ptr<DiskRead>(new DiskRead());
|
||||||
|
diskWriteDriver = std::unique_ptr<DiskWrite>(new DiskWrite());
|
||||||
setupSupportedRXNetworks(supportedRXNetworks);
|
setupSupportedRXNetworks(supportedRXNetworks);
|
||||||
setupSupportedTXNetworks(supportedTXNetworks);
|
setupSupportedTXNetworks(supportedTXNetworks);
|
||||||
setupExtensions();
|
setupExtensions();
|
||||||
|
|
@ -272,10 +370,6 @@ protected:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Driver>
|
|
||||||
std::unique_ptr<Driver> makeDriver() { return std::unique_ptr<Driver>(new Driver(report, getWritableNeoDevice())); }
|
|
||||||
virtual void setupDriver(Driver&) {}
|
|
||||||
|
|
||||||
virtual std::unique_ptr<Packetizer> makePacketizer() { return std::unique_ptr<Packetizer>(new Packetizer(report)); }
|
virtual std::unique_ptr<Packetizer> makePacketizer() { return std::unique_ptr<Packetizer>(new Packetizer(report)); }
|
||||||
virtual void setupPacketizer(Packetizer&) {}
|
virtual void setupPacketizer(Packetizer&) {}
|
||||||
std::unique_ptr<Packetizer> makeConfiguredPacketizer() {
|
std::unique_ptr<Packetizer> makeConfiguredPacketizer() {
|
||||||
|
|
@ -295,7 +389,9 @@ protected:
|
||||||
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer,
|
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer,
|
||||||
std::unique_ptr<Encoder> e,
|
std::unique_ptr<Encoder> e,
|
||||||
std::unique_ptr<Decoder> d) { return std::make_shared<Communication>(report, std::move(t), makeConfiguredPacketizer, std::move(e), std::move(d)); }
|
std::unique_ptr<Decoder> d) { return std::make_shared<Communication>(report, std::move(t), makeConfiguredPacketizer, std::move(e), std::move(d)); }
|
||||||
virtual void setupCommunication(Communication&) {}
|
virtual void setupCommunication(Communication& communication) {
|
||||||
|
communication.packetizer = communication.makeConfiguredPacketizer();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Settings>
|
template<typename Settings>
|
||||||
std::unique_ptr<IDeviceSettings> makeSettings(std::shared_ptr<Communication> com) {
|
std::unique_ptr<IDeviceSettings> makeSettings(std::shared_ptr<Communication> com) {
|
||||||
|
|
@ -328,7 +424,7 @@ protected:
|
||||||
|
|
||||||
void handleInternalMessage(std::shared_ptr<Message> message);
|
void handleInternalMessage(std::shared_ptr<Message> message);
|
||||||
|
|
||||||
virtual void handleDeviceStatus(const std::shared_ptr<Message>&) {}
|
virtual void handleDeviceStatus(const std::shared_ptr<RawMessage>&) {}
|
||||||
|
|
||||||
neodevice_t& getWritableNeoDevice() { return data; }
|
neodevice_t& getWritableNeoDevice() { return data; }
|
||||||
|
|
||||||
|
|
@ -337,6 +433,10 @@ private:
|
||||||
std::shared_ptr<ResetStatusMessage> latestResetStatus;
|
std::shared_ptr<ResetStatusMessage> latestResetStatus;
|
||||||
std::vector<optional<DeviceAppVersion>> versions;
|
std::vector<optional<DeviceAppVersion>> versions;
|
||||||
|
|
||||||
|
mutable std::mutex diskLock;
|
||||||
|
std::unique_ptr<Disk::ReadDriver> diskReadDriver;
|
||||||
|
std::unique_ptr<Disk::WriteDriver> diskWriteDriver;
|
||||||
|
|
||||||
mutable std::mutex extensionsLock;
|
mutable std::mutex extensionsLock;
|
||||||
std::vector<std::shared_ptr<DeviceExtension>> extensions;
|
std::vector<std::shared_ptr<DeviceExtension>> extensions;
|
||||||
void forEachExtension(std::function<bool(const std::shared_ptr<DeviceExtension>&)> fn);
|
void forEachExtension(std::function<bool(const std::shared_ptr<DeviceExtension>&)> fn);
|
||||||
|
|
@ -369,6 +469,7 @@ private:
|
||||||
void enforcePollingMessageLimit();
|
void enforcePollingMessageLimit();
|
||||||
|
|
||||||
std::atomic<bool> stopHeartbeatThread{false};
|
std::atomic<bool> stopHeartbeatThread{false};
|
||||||
|
std::mutex heartbeatMutex;
|
||||||
std::thread heartbeatThread;
|
std::thread heartbeatThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public:
|
||||||
RADSupermoon = (0x00000003),
|
RADSupermoon = (0x00000003),
|
||||||
DW_VCAN = (0x00000004),
|
DW_VCAN = (0x00000004),
|
||||||
RADMoon2 = (0x00000005),
|
RADMoon2 = (0x00000005),
|
||||||
RADGigalog = (0x00000006),
|
RADMars = (0x00000006),
|
||||||
VCAN4_1 = (0x00000007),
|
VCAN4_1 = (0x00000007),
|
||||||
FIRE = (0x00000008),
|
FIRE = (0x00000008),
|
||||||
RADPluto = (0x00000009),
|
RADPluto = (0x00000009),
|
||||||
|
|
@ -95,8 +95,8 @@ public:
|
||||||
return "DW_VCAN";
|
return "DW_VCAN";
|
||||||
case RADMoon2:
|
case RADMoon2:
|
||||||
return "RAD-Moon 2";
|
return "RAD-Moon 2";
|
||||||
case RADGigalog:
|
case RADMars:
|
||||||
return "RAD-Gigalog";
|
return "RAD-Mars";
|
||||||
case VCAN4_1:
|
case VCAN4_1:
|
||||||
return "ValueCAN 4-1";
|
return "ValueCAN 4-1";
|
||||||
case FIRE:
|
case FIRE:
|
||||||
|
|
@ -203,7 +203,7 @@ private:
|
||||||
#define ICSNEO_DEVICETYPE_RADSUPERMOON ((devicetype_t)0x00000003)
|
#define ICSNEO_DEVICETYPE_RADSUPERMOON ((devicetype_t)0x00000003)
|
||||||
#define ICSNEO_DEVICETYPE_DW_VCAN ((devicetype_t)0x00000004)
|
#define ICSNEO_DEVICETYPE_DW_VCAN ((devicetype_t)0x00000004)
|
||||||
#define ICSNEO_DEVICETYPE_RADMOON2 ((devicetype_t)0x00000005)
|
#define ICSNEO_DEVICETYPE_RADMOON2 ((devicetype_t)0x00000005)
|
||||||
#define ICSNEO_DEVICETYPE_RADGIGALOG ((devicetype_t)0x00000006)
|
#define ICSNEO_DEVICETYPE_RADMARS ((devicetype_t)0x00000006)
|
||||||
#define ICSNEO_DEVICETYPE_VCAN4_1 ((devicetype_t)0x00000007)
|
#define ICSNEO_DEVICETYPE_VCAN4_1 ((devicetype_t)0x00000007)
|
||||||
#define ICSNEO_DEVICETYPE_FIRE ((devicetype_t)0x00000008)
|
#define ICSNEO_DEVICETYPE_FIRE ((devicetype_t)0x00000008)
|
||||||
#define ICSNEO_DEVICETYPE_RADPLUTO ((devicetype_t)0x00000009)
|
#define ICSNEO_DEVICETYPE_RADPLUTO ((devicetype_t)0x00000009)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
static void AddBuiltInExtensionsTo([[maybe_unused]] const std::shared_ptr<icsneo::Device>& device) {
|
static void AddBuiltInExtensionsTo(const std::shared_ptr<icsneo::Device>& device) {
|
||||||
|
(void)device; // [[maybe_unused]]
|
||||||
@LIBICSNEO_EXT_CODE@
|
@LIBICSNEO_EXT_CODE@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public:
|
||||||
virtual void handleMessage(const std::shared_ptr<Message>&) {}
|
virtual void handleMessage(const std::shared_ptr<Message>&) {}
|
||||||
|
|
||||||
// Return true to continue transmitting, success should be written to if false is returned
|
// Return true to continue transmitting, success should be written to if false is returned
|
||||||
virtual bool transmitHook(const std::shared_ptr<Message>& message, bool& success) { (void)message; (void)success; return true; }
|
virtual bool transmitHook(const std::shared_ptr<Frame>& frame, bool& success) { (void)frame; (void)success; return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Device& device;
|
Device& device;
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ private:
|
||||||
bool startWhenGoingOnline = false;
|
bool startWhenGoingOnline = false;
|
||||||
bool allowColdstart = false;
|
bool allowColdstart = false;
|
||||||
bool wakeupBeforeStart = false;
|
bool wakeupBeforeStart = false;
|
||||||
|
bool lastSeenRunning = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#define neoflexray_controller_config_t icsneo::FlexRay::Controller::Configuration
|
#define neoflexray_controller_config_t icsneo::FlexRay::Controller::Configuration
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public:
|
||||||
void onGoOffline() override;
|
void onGoOffline() override;
|
||||||
|
|
||||||
void handleMessage(const std::shared_ptr<Message>& message) override;
|
void handleMessage(const std::shared_ptr<Message>& message) override;
|
||||||
bool transmitHook(const std::shared_ptr<Message>& message, bool& success) override;
|
bool transmitHook(const std::shared_ptr<Frame>& frame, bool& success) override;
|
||||||
|
|
||||||
std::shared_ptr<Controller> getController(uint8_t index) const {
|
std::shared_ptr<Controller> getController(uint8_t index) const {
|
||||||
if(index >= controllers.size())
|
if(index >= controllers.size())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef __FOUNDDEVICE_H_
|
||||||
|
#define __FOUNDDEVICE_H_
|
||||||
|
|
||||||
|
#include "icsneo/communication/driver.h"
|
||||||
|
#include "icsneo/device/neodevice.h"
|
||||||
|
|
||||||
|
namespace icsneo {
|
||||||
|
|
||||||
|
typedef std::function< std::unique_ptr<Driver>(device_eventhandler_t err, neodevice_t& forDevice) > driver_factory_t;
|
||||||
|
|
||||||
|
class FoundDevice {
|
||||||
|
public:
|
||||||
|
neodevice_handle_t handle = 0;
|
||||||
|
char serial[7] = {};
|
||||||
|
uint16_t productId = 0;
|
||||||
|
driver_factory_t makeDriver;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace icsneo
|
||||||
|
|
||||||
|
#endif // __FOUNDDEVICE_H_
|
||||||
|
|
@ -384,6 +384,26 @@ typedef struct LOGGER_SETTINGS_t
|
||||||
} LOGGER_SETTINGS;
|
} LOGGER_SETTINGS;
|
||||||
#define LOGGER_SETTINGS_SIZE 4
|
#define LOGGER_SETTINGS_SIZE 4
|
||||||
|
|
||||||
|
#define RAD_GPTP_NUM_PORTS 1 // 1 because only supported as gPTP endpoint
|
||||||
|
typedef struct RAD_GPTP_SETTINGS_t
|
||||||
|
{
|
||||||
|
uint32_t neighborPropDelayThresh;//ns
|
||||||
|
uint32_t sys_phc_sync_interval;//ns
|
||||||
|
int8_t logPDelayReqInterval;// log2ms
|
||||||
|
int8_t logSyncInterval;// log2ms
|
||||||
|
int8_t logAnnounceInterval;// log2ms
|
||||||
|
uint8_t profile;
|
||||||
|
uint8_t priority1;
|
||||||
|
uint8_t clockclass;
|
||||||
|
uint8_t clockaccuracy;
|
||||||
|
uint8_t priority2;
|
||||||
|
uint16_t offset_scaled_log_variance;
|
||||||
|
uint8_t gPTPportRole[RAD_GPTP_NUM_PORTS];
|
||||||
|
uint8_t portEnable[RAD_GPTP_NUM_PORTS];
|
||||||
|
uint8_t rsvd[16];
|
||||||
|
} RAD_GPTP_SETTINGS;//36 Bytes with RAD_GPTP_NUM_PORTS = 1
|
||||||
|
#define RAD_GPTP_SETTINGS_SIZE 36
|
||||||
|
|
||||||
#define RAD_REPORTING_SETTINGS_FLAG_TEMP_ENABLE 0x00000001
|
#define RAD_REPORTING_SETTINGS_FLAG_TEMP_ENABLE 0x00000001
|
||||||
#define RAD_REPORTING_SETTINGS_FLAG_MIC2_GPS_ENABLE 0x00000002 // USB port 1
|
#define RAD_REPORTING_SETTINGS_FLAG_MIC2_GPS_ENABLE 0x00000002 // USB port 1
|
||||||
#define RAD_REPORTING_SETTINGS_FLAG_INT_GPS_ENABLE 0x00000004
|
#define RAD_REPORTING_SETTINGS_FLAG_INT_GPS_ENABLE 0x00000004
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
|
class FoundDevice;
|
||||||
|
|
||||||
}
|
}
|
||||||
typedef icsneo::Device* devicehandle_t;
|
typedef icsneo::Device* devicehandle_t;
|
||||||
|
|
@ -20,7 +21,13 @@ typedef int32_t neodevice_handle_t;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
typedef struct neodevice_t {
|
||||||
|
neodevice_t();
|
||||||
|
neodevice_t(const icsneo::FoundDevice& found, devicetype_t inType);
|
||||||
|
#else
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
#endif
|
||||||
devicehandle_t device; // Pointer back to the C++ device object
|
devicehandle_t device; // Pointer back to the C++ device object
|
||||||
neodevice_handle_t handle; // Handle for use by the underlying driver
|
neodevice_handle_t handle; // Handle for use by the underlying driver
|
||||||
devicetype_t type;
|
devicetype_t type;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/communication/packetizer.h"
|
#include "icsneo/communication/packetizer.h"
|
||||||
#include "icsneo/communication/decoder.h"
|
#include "icsneo/communication/decoder.h"
|
||||||
#include "icsneo/platform/cdcacm.h"
|
|
||||||
#include "icsneo/device/tree/etherbadge/etherbadgesettings.h"
|
#include "icsneo/device/tree/etherbadge/etherbadgesettings.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
@ -15,49 +14,35 @@ namespace icsneo {
|
||||||
class EtherBADGE : public Device {
|
class EtherBADGE : public Device {
|
||||||
public:
|
public:
|
||||||
// Serial numbers start with EB
|
// Serial numbers start with EB
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::EtherBADGE;
|
// USB PID is 0x1107, standard driver is CDCACM
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x1107;
|
ICSNEO_FINDABLE_DEVICE(EtherBADGE, DeviceType::EtherBADGE, "EB");
|
||||||
static constexpr const char* SERIAL_START = "EB";
|
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new EtherBADGE(neodevice));
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
Network::NetID::HSCAN,
|
Network::NetID::HSCAN,
|
||||||
|
|
||||||
Network::NetID::LIN,
|
Network::NetID::LIN,
|
||||||
|
|
||||||
Network::NetID::OP_Ethernet1
|
Network::NetID::OP_Ethernet1
|
||||||
};
|
};
|
||||||
return supportedNetworks;
|
return supportedNetworks;
|
||||||
}
|
}
|
||||||
|
|
||||||
EtherBADGE(neodevice_t neodevice) : Device(neodevice) {
|
protected:
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
EtherBADGE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
productId = PRODUCT_ID;
|
initialize<EtherBADGESettings>(makeDriver);
|
||||||
initialize<CDCACM, EtherBADGESettings>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void setupEncoder(Encoder& encoder) override {
|
virtual void setupEncoder(Encoder& encoder) override {
|
||||||
Device::setupEncoder(encoder);
|
Device::setupEncoder(encoder);
|
||||||
encoder.supportCANFD = true;
|
encoder.supportCANFD = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
|
|
||||||
bool requiresVehiclePower() const override { return false; }
|
bool requiresVehiclePower() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,14 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/cdcacm.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoOBD2PRO : public Device {
|
class NeoOBD2PRO : public Device {
|
||||||
public:
|
public:
|
||||||
// Serial numbers are NP****
|
// Serial numbers start with NP
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::OBD2_PRO;
|
// USB PID is 0x1103, standard driver is CDCACM
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x1103;
|
ICSNEO_FINDABLE_DEVICE(NeoOBD2PRO, DeviceType::OBD2_PRO, "NP");
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new NeoOBD2PRO(neodevice));
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
|
|
@ -32,19 +23,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoOBD2PRO(neodevice_t neodevice) : Device(neodevice) {
|
NeoOBD2PRO(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
initialize<CDCACM>();
|
initialize(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
|
|
||||||
bool requiresVehiclePower() const override { return false; }
|
bool requiresVehiclePower() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,14 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/cdcacm.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoOBD2SIM : public Device {
|
class NeoOBD2SIM : public Device {
|
||||||
public:
|
public:
|
||||||
// Serial numbers are OS****
|
// Serial numbers start with OS
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::OBD2_SIM;
|
// USB PID is 0x1100, standard driver is CDCACM
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x1100;
|
ICSNEO_FINDABLE_DEVICE(NeoOBD2SIM, DeviceType::OBD2_SIM, "OS");
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new NeoOBD2SIM(neodevice));
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
|
|
@ -32,19 +23,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoOBD2SIM(neodevice_t neodevice) : Device(neodevice) {
|
NeoOBD2SIM(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
initialize<CDCACM>();
|
initialize(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
|
|
||||||
bool requiresVehiclePower() const override { return false; }
|
bool requiresVehiclePower() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,14 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/ftdi.h"
|
|
||||||
#include "icsneo/device/tree/neovifire/neovifiresettings.h"
|
#include "icsneo/device/tree/neovifire/neovifiresettings.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoVIFIRE : public Device {
|
class NeoVIFIRE : public Device {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::FIRE;
|
// USB PID is 0x0701, standard driver is FTDI
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x0701;
|
ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIFIRE, DeviceType::FIRE, 0x0701);
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new NeoVIFIRE(neodevice)); // Creation of the shared_ptr
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
|
|
@ -67,19 +58,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoVIFIRE(neodevice_t neodevice) : Device(neodevice) {
|
NeoVIFIRE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
initialize<FTDI, NeoVIFIRESettings>();
|
initialize<NeoVIFIRESettings>(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,16 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/ftdi.h"
|
|
||||||
#include "icsneo/device/tree/neovifire2/neovifire2settings.h"
|
#include "icsneo/device/tree/neovifire2/neovifire2settings.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoVIFIRE2 : public Device {
|
class NeoVIFIRE2 : public Device {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::FIRE2;
|
// Serial numbers start with CY
|
||||||
static constexpr const char* SERIAL_START = "CY";
|
// USB PID is 0x1000, standard driver is FTDI
|
||||||
|
// Ethernet MAC allocation is 0x04, standard driver is Raw
|
||||||
|
ICSNEO_FINDABLE_DEVICE(NeoVIFIRE2, DeviceType::FIRE2, "CY");
|
||||||
|
|
||||||
enum class SKU {
|
enum class SKU {
|
||||||
Standard,
|
Standard,
|
||||||
|
|
@ -87,8 +88,22 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NeoVIFIRE2(neodevice_t neodevice) : Device(neodevice) {
|
NeoVIFIRE2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
initialize<NeoVIFIRE2Settings>(makeDriver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupSettings(IDeviceSettings& ssettings) override {
|
||||||
|
if(com->driver->isEthernet()) {
|
||||||
|
// TODO Check firmware version, old firmwares will reset Ethernet settings on settings send
|
||||||
|
ssettings.readonly = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool currentDriverSupportsDFU() const override { return com->driver->isEthernet(); }
|
||||||
|
|
||||||
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
|
Device::setupPacketizer(packetizer);
|
||||||
|
packetizer.align16bit = !com->driver->isEthernet();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupEncoder(Encoder& encoder) override {
|
virtual void setupEncoder(Encoder& encoder) override {
|
||||||
|
|
@ -96,16 +111,16 @@ protected:
|
||||||
encoder.supportCANFD = true;
|
encoder.supportCANFD = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
|
|
||||||
void handleDeviceStatus(const std::shared_ptr<Message>& message) override {
|
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
|
||||||
if(!message || message->data.size() < sizeof(neovifire2_status_t))
|
if(message->data.size() < sizeof(neovifire2_status_t))
|
||||||
return;
|
return;
|
||||||
std::lock_guard<std::mutex> lk(ioMutex);
|
std::lock_guard<std::mutex> lk(ioMutex);
|
||||||
const neovifire2_status_t* status = reinterpret_cast<const neovifire2_status_t*>(message->data.data());
|
const neovifire2_status_t* status = reinterpret_cast<const neovifire2_status_t*>(message->data.data());
|
||||||
|
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
#ifndef __NEOVIFIRE2ETH_H_
|
|
||||||
#define __NEOVIFIRE2ETH_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
#include "icsneo/device/tree/neovifire2/neovifire2.h"
|
|
||||||
#include "icsneo/platform/pcap.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace icsneo {
|
|
||||||
|
|
||||||
class NeoVIFIRE2ETH : public NeoVIFIRE2 {
|
|
||||||
public:
|
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x0004;
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto& foundDev : pcapDevices) {
|
|
||||||
auto fakedev = std::shared_ptr<NeoVIFIRE2ETH>(new NeoVIFIRE2ETH({}));
|
|
||||||
for (auto& payload : foundDev.discoveryPackets)
|
|
||||||
fakedev->com->packetizer->input(payload);
|
|
||||||
for (auto& packet : fakedev->com->packetizer->output()) {
|
|
||||||
std::shared_ptr<Message> msg;
|
|
||||||
if (!fakedev->com->decoder->decode(msg, packet))
|
|
||||||
continue; // We failed to decode this packet
|
|
||||||
|
|
||||||
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
|
|
||||||
continue; // Not a message we care about
|
|
||||||
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
|
|
||||||
if(!sn)
|
|
||||||
continue; // Not a serial number message
|
|
||||||
|
|
||||||
if(sn->deviceSerial.length() < 2)
|
|
||||||
continue;
|
|
||||||
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
|
|
||||||
continue; // Not a FIRE 2
|
|
||||||
|
|
||||||
auto device = foundDev.device;
|
|
||||||
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
|
|
||||||
found.push_back(std::make_shared<NeoVIFIRE2ETH>(std::move(device)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
NeoVIFIRE2ETH(neodevice_t neodevice) : NeoVIFIRE2(neodevice) {
|
|
||||||
initialize<PCAP, NeoVIFIRE2Settings>();
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool currentDriverSupportsDFU() const override { return false; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setupSettings(IDeviceSettings& ssettings) override {
|
|
||||||
// TODO Check firmware version, old firmwares will reset Ethernet settings on settings send
|
|
||||||
ssettings.readonly = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef __NEOVIFIRE2USB_H_
|
|
||||||
#define __NEOVIFIRE2USB_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
#include "icsneo/device/tree/neovifire2/neovifire2.h"
|
|
||||||
#include "icsneo/platform/ftdi.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
|
||||||
|
|
||||||
class NeoVIFIRE2USB : public NeoVIFIRE2 {
|
|
||||||
public:
|
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x1000;
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new NeoVIFIRE2USB(neodevice)); // Creation of the shared_ptr
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
NeoVIFIRE2USB(neodevice_t neodevice) : NeoVIFIRE2(neodevice) {
|
|
||||||
initialize<FTDI, NeoVIFIRE2Settings>();
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -3,48 +3,17 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/pcap.h"
|
#include "icsneo/disk/extextractordiskreaddriver.h"
|
||||||
|
#include "icsneo/disk/neomemorydiskdriver.h"
|
||||||
#include "icsneo/device/tree/neovired2/neovired2settings.h"
|
#include "icsneo/device/tree/neovired2/neovired2settings.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoVIRED2 : public Device {
|
class NeoVIRED2 : public Device {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RED2;
|
// Serial numbers start with D2
|
||||||
static constexpr const char* SERIAL_START = "D2";
|
// Ethernet MAC allocation is 0x0E, standard driver is Raw
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x000E;
|
ICSNEO_FINDABLE_DEVICE(NeoVIRED2, DeviceType::RED2, "D2");
|
||||||
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto& foundDev : pcapDevices) {
|
|
||||||
auto fakedev = std::shared_ptr<NeoVIRED2>(new NeoVIRED2({}));
|
|
||||||
for (auto& payload : foundDev.discoveryPackets)
|
|
||||||
fakedev->com->packetizer->input(payload);
|
|
||||||
for (auto& packet : fakedev->com->packetizer->output()) {
|
|
||||||
std::shared_ptr<Message> msg;
|
|
||||||
if (!fakedev->com->decoder->decode(msg, packet))
|
|
||||||
continue; // We failed to decode this packet
|
|
||||||
|
|
||||||
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
|
|
||||||
continue; // Not a message we care about
|
|
||||||
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
|
|
||||||
if(!sn)
|
|
||||||
continue; // Not a serial number message
|
|
||||||
|
|
||||||
if(sn->deviceSerial.length() < 2)
|
|
||||||
continue;
|
|
||||||
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
|
|
||||||
continue; // Not a RED 2
|
|
||||||
|
|
||||||
auto device = foundDev.device;
|
|
||||||
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
|
|
||||||
found.emplace_back(new NeoVIRED2(std::move(device)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
|
|
@ -66,10 +35,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NeoVIRED2(neodevice_t neodevice) : Device(neodevice) {
|
NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
initialize<PCAP, NeoVIRED2Settings>();
|
initialize<NeoVIRED2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupEncoder(Encoder& encoder) override {
|
virtual void setupEncoder(Encoder& encoder) override {
|
||||||
|
|
@ -77,13 +44,18 @@ protected:
|
||||||
encoder.supportCANFD = true;
|
encoder.supportCANFD = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
|
Device::setupPacketizer(packetizer);
|
||||||
|
packetizer.align16bit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ namespace icsneo {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4201) // nameless struct/union
|
||||||
|
#endif
|
||||||
|
|
||||||
#pragma pack(push, 2)
|
#pragma pack(push, 2)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t perf_en;
|
uint16_t perf_en;
|
||||||
|
|
@ -57,8 +62,7 @@ typedef struct {
|
||||||
ETHERNET_SETTINGS ethernet;
|
ETHERNET_SETTINGS ethernet;
|
||||||
TIMESYNC_ICSHARDWARE_SETTINGS timeSync;
|
TIMESYNC_ICSHARDWARE_SETTINGS timeSync;
|
||||||
STextAPISettings text_api;
|
STextAPISettings text_api;
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
uint32_t disableUsbCheckOnBoot : 1;
|
uint32_t disableUsbCheckOnBoot : 1;
|
||||||
uint32_t enableLatencyTest : 1;
|
uint32_t enableLatencyTest : 1;
|
||||||
uint32_t busMessagesToAndroid : 1;
|
uint32_t busMessagesToAndroid : 1;
|
||||||
|
|
@ -87,6 +91,10 @@ typedef struct {
|
||||||
} neovired2_status_t;
|
} neovired2_status_t;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,19 @@
|
||||||
|
|
||||||
#include "icsneo/device/tree/plasion/plasion.h"
|
#include "icsneo/device/tree/plasion/plasion.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/ftdi.h"
|
#include "icsneo/disk/plasiondiskreaddriver.h"
|
||||||
|
#include "icsneo/disk/neomemorydiskdriver.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoVIION : public Plasion {
|
class NeoVIION : public Plasion {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::ION;
|
// USB PID is 0x0901, standard driver is FTDI
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x0901;
|
ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIION, DeviceType::ION, 0x0901);
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new NeoVIION(neodevice));
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoVIION(neodevice_t neodevice) : Plasion(neodevice) {
|
NeoVIION(neodevice_t neodevice, const driver_factory_t& makeDriver) : Plasion(neodevice) {
|
||||||
initialize<FTDI>();
|
initialize<NullSettings, Disk::PlasionDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::shared_ptr<Communication> makeCommunication(
|
virtual std::shared_ptr<Communication> makeCommunication(
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,17 @@
|
||||||
|
|
||||||
#include "icsneo/device/tree/plasion/plasion.h"
|
#include "icsneo/device/tree/plasion/plasion.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/ftdi.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class NeoVIPLASMA : public Plasion {
|
class NeoVIPLASMA : public Plasion {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::PLASMA;
|
// USB PID is 0x0801, standard driver is FTDI
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x0801;
|
ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIPLASMA, DeviceType::PLASMA, 0x0801);
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new NeoVIPLASMA(neodevice));
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NeoVIPLASMA(neodevice_t neodevice) : Plasion(neodevice) {
|
NeoVIPLASMA(neodevice_t neodevice, const driver_factory_t& makeDriver) : Plasion(neodevice) {
|
||||||
initialize<FTDI>();
|
initialize<NullSettings, Disk::PlasionDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::shared_ptr<Communication> makeCommunication(
|
virtual std::shared_ptr<Communication> makeCommunication(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/communication/multichannelcommunication.h"
|
#include "icsneo/communication/multichannelcommunication.h"
|
||||||
#include "icsneo/platform/ftdi.h"
|
|
||||||
#include "icsneo/device/extensions/flexray/extension.h"
|
#include "icsneo/device/extensions/flexray/extension.h"
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
@ -45,6 +44,8 @@ public:
|
||||||
size_t getEthernetActivationLineCount() const override { return 1; }
|
size_t getEthernetActivationLineCount() const override { return 1; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using Device::Device;
|
||||||
|
|
||||||
// TODO This is done so that Plasion can still transmit it's basic networks, awaiting slave VNET support
|
// TODO This is done so that Plasion can still transmit it's basic networks, awaiting slave VNET support
|
||||||
virtual bool isSupportedRXNetwork(const Network&) const override { return true; }
|
virtual bool isSupportedRXNetwork(const Network&) const override { return true; }
|
||||||
virtual bool isSupportedTXNetwork(const Network&) const override { return true; }
|
virtual bool isSupportedTXNetwork(const Network&) const override { return true; }
|
||||||
|
|
@ -55,7 +56,7 @@ protected:
|
||||||
addExtension(std::make_shared<FlexRay::Extension>(*this, flexRayControllers));
|
addExtension(std::make_shared<FlexRay::Extension>(*this, flexRayControllers));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
// TODO Check configuration for FlexRay ColdStart mode, disable FlexRay 2 if so
|
// TODO Check configuration for FlexRay ColdStart mode, disable FlexRay 2 if so
|
||||||
|
|
@ -80,16 +81,13 @@ protected:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDeviceStatus(const std::shared_ptr<Message>& message) override {
|
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
|
||||||
if(!message || message->data.size() < sizeof(fire2vnet_status_t))
|
if(message->data.size() < sizeof(fire2vnet_status_t))
|
||||||
return;
|
return;
|
||||||
std::lock_guard<std::mutex> lk(ioMutex);
|
std::lock_guard<std::mutex> lk(ioMutex);
|
||||||
const fire2vnet_status_t* status = reinterpret_cast<const fire2vnet_status_t*>(message->data.data());
|
const fire2vnet_status_t* status = reinterpret_cast<const fire2vnet_status_t*>(message->data.data());
|
||||||
ethActivationStatus = status->ethernetActivationLineEnabled;
|
ethActivationStatus = status->ethernetActivationLineEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
Plasion(neodevice_t neodevice) : Device(neodevice) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,14 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/cdcacm.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class RADEpsilon : public Device {
|
class RADEpsilon : public Device {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADEpsilon;
|
// Serial numbers start with RE
|
||||||
static constexpr const char* SERIAL_START = "RE";
|
// USB PID is 0x1109, standard driver is CDCACM
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x1109;
|
ICSNEO_FINDABLE_DEVICE(RADEpsilon, DeviceType::RADEpsilon, "RE");
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new RADEpsilon(neodevice));
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
|
|
@ -34,10 +25,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RADEpsilon(neodevice_t neodevice) : Device(neodevice) {
|
RADEpsilon(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
initialize<CDCACM>();
|
initialize(makeDriver);
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupEncoder(Encoder& encoder) override {
|
virtual void setupEncoder(Encoder& encoder) override {
|
||||||
|
|
@ -45,13 +34,13 @@ protected:
|
||||||
encoder.supportCANFD = true;
|
encoder.supportCANFD = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
for(auto& netid : GetSupportedNetworks())
|
for(auto& netid : GetSupportedNetworks())
|
||||||
rxNetworks.emplace_back(netid);
|
rxNetworks.emplace_back(netid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include "icsneo/device/device.h"
|
#include "icsneo/device/device.h"
|
||||||
#include "icsneo/device/devicetype.h"
|
#include "icsneo/device/devicetype.h"
|
||||||
#include "icsneo/platform/pcap.h"
|
|
||||||
#include "icsneo/communication/packetizer.h"
|
#include "icsneo/communication/packetizer.h"
|
||||||
#include "icsneo/communication/decoder.h"
|
#include "icsneo/communication/decoder.h"
|
||||||
#include "icsneo/device/tree/radgalaxy/radgalaxysettings.h"
|
#include "icsneo/device/tree/radgalaxy/radgalaxysettings.h"
|
||||||
|
|
@ -15,41 +14,8 @@ namespace icsneo {
|
||||||
class RADGalaxy : public Device {
|
class RADGalaxy : public Device {
|
||||||
public:
|
public:
|
||||||
// Serial numbers start with RG
|
// Serial numbers start with RG
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGalaxy;
|
// Ethernet MAC allocation is 0x03, standard driver is Raw
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x0003;
|
ICSNEO_FINDABLE_DEVICE(RADGalaxy, DeviceType::RADGalaxy, "RG");
|
||||||
static constexpr const char* SERIAL_START = "RG";
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto& foundDev : pcapDevices) {
|
|
||||||
auto fakedev = std::shared_ptr<RADGalaxy>(new RADGalaxy({}));
|
|
||||||
for(auto& payload : foundDev.discoveryPackets)
|
|
||||||
fakedev->com->packetizer->input(payload);
|
|
||||||
for(auto& packet : fakedev->com->packetizer->output()) {
|
|
||||||
std::shared_ptr<Message> msg;
|
|
||||||
if(!fakedev->com->decoder->decode(msg, packet))
|
|
||||||
continue; // We failed to decode this packet
|
|
||||||
|
|
||||||
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
|
|
||||||
continue; // Not a message we care about
|
|
||||||
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
|
|
||||||
if(!sn)
|
|
||||||
continue; // Not a serial number message
|
|
||||||
|
|
||||||
if(sn->deviceSerial.length() < 2)
|
|
||||||
continue;
|
|
||||||
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
|
|
||||||
continue; // Not a RADGalaxy
|
|
||||||
|
|
||||||
auto device = foundDev.device;
|
|
||||||
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
|
|
||||||
found.emplace_back(new RADGalaxy(std::move(device)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::vector<Network>& GetSupportedNetworks() {
|
static const std::vector<Network>& GetSupportedNetworks() {
|
||||||
static std::vector<Network> supportedNetworks = {
|
static std::vector<Network> supportedNetworks = {
|
||||||
|
|
@ -85,15 +51,13 @@ public:
|
||||||
return supportedNetworks;
|
return supportedNetworks;
|
||||||
}
|
}
|
||||||
|
|
||||||
RADGalaxy(neodevice_t neodevice) : Device(neodevice) {
|
|
||||||
initialize<PCAP, RADGalaxySettings>();
|
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getEthernetActivationLineCount() const override { return 1; }
|
size_t getEthernetActivationLineCount() const override { return 1; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
RADGalaxy(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
|
initialize<RADGalaxySettings>(makeDriver);
|
||||||
|
}
|
||||||
|
|
||||||
void setupPacketizer(Packetizer& packetizer) override {
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
Device::setupPacketizer(packetizer);
|
Device::setupPacketizer(packetizer);
|
||||||
packetizer.disableChecksum = true;
|
packetizer.disableChecksum = true;
|
||||||
|
|
@ -118,8 +82,8 @@ protected:
|
||||||
// The supported TX networks are the same as the supported RX networks for this device
|
// The supported TX networks are the same as the supported RX networks for this device
|
||||||
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||||
|
|
||||||
void handleDeviceStatus(const std::shared_ptr<Message>& message) override {
|
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
|
||||||
if(!message || message->data.size() < sizeof(radgalaxy_status_t))
|
if(message->data.size() < sizeof(radgalaxy_status_t))
|
||||||
return;
|
return;
|
||||||
std::lock_guard<std::mutex> lk(ioMutex);
|
std::lock_guard<std::mutex> lk(ioMutex);
|
||||||
const radgalaxy_status_t* status = reinterpret_cast<const radgalaxy_status_t*>(message->data.data());
|
const radgalaxy_status_t* status = reinterpret_cast<const radgalaxy_status_t*>(message->data.data());
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,12 @@ typedef struct {
|
||||||
RAD_REPORTING_SETTINGS reporting;
|
RAD_REPORTING_SETTINGS reporting;
|
||||||
DISK_SETTINGS disk;
|
DISK_SETTINGS disk;
|
||||||
LOGGER_SETTINGS logger;
|
LOGGER_SETTINGS logger;
|
||||||
|
|
||||||
|
ETHERNET_SETTINGS2 ethernet1;// DAQ port on label, NETID_ETHERNET
|
||||||
|
ETHERNET_SETTINGS2 ethernet2;// LAN port on label, NETID_ETHERNET2
|
||||||
|
uint16_t network_enables_4;
|
||||||
|
|
||||||
|
RAD_GPTP_SETTINGS gPTP;
|
||||||
} radgalaxy_settings_t;
|
} radgalaxy_settings_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
#ifndef __RADGIGALOG_ETH_H_
|
|
||||||
#define __RADGIGALOG_ETH_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
#include "icsneo/device/tree/radgigalog/radgigalog.h"
|
|
||||||
#include "icsneo/platform/pcap.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
|
||||||
|
|
||||||
class RADGigalogETH : public RADGigalog {
|
|
||||||
public:
|
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x000A;
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto& foundDev : pcapDevices) {
|
|
||||||
auto fakedev = std::shared_ptr<RADGigalogETH>(new RADGigalogETH({}));
|
|
||||||
for (auto& payload : foundDev.discoveryPackets)
|
|
||||||
fakedev->com->packetizer->input(payload);
|
|
||||||
for (auto& packet : fakedev->com->packetizer->output()) {
|
|
||||||
std::shared_ptr<Message> msg;
|
|
||||||
if (!fakedev->com->decoder->decode(msg, packet))
|
|
||||||
continue; // We failed to decode this packet
|
|
||||||
|
|
||||||
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
|
|
||||||
continue; // Not a message we care about
|
|
||||||
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
|
|
||||||
if(!sn)
|
|
||||||
continue; // Not a serial number message
|
|
||||||
|
|
||||||
if(sn->deviceSerial.length() < 2)
|
|
||||||
continue;
|
|
||||||
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
|
|
||||||
continue; // Not a RADGigalog
|
|
||||||
|
|
||||||
auto device = foundDev.device;
|
|
||||||
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
|
|
||||||
found.push_back(std::shared_ptr<RADGigalogETH>(new RADGigalogETH(std::move(device))));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RADGigalogETH(neodevice_t neodevice) : RADGigalog(neodevice) {
|
|
||||||
initialize<PCAP, RADGigalogSettings>();
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
#ifndef __RADGIGALOG_USB_H_
|
|
||||||
#define __RADGIGALOG_USB_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
#include "icsneo/device/tree/radgigalog/radgigalog.h"
|
|
||||||
#include "icsneo/platform/ftdi3.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
|
||||||
|
|
||||||
class RADGigalogUSB : public RADGigalog {
|
|
||||||
public:
|
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x1203;
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find() {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto neodevice : FTDI3::FindByProduct(PRODUCT_ID))
|
|
||||||
found.emplace_back(new RADGigalogUSB(neodevice)); // Creation of the shared_ptr
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RADGigalogUSB(neodevice_t neodevice) : RADGigalog(neodevice) {
|
|
||||||
initialize<FTDI3, RADGigalogSettings>();
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -11,14 +11,18 @@ namespace icsneo {
|
||||||
|
|
||||||
class RADGigastar : public Device {
|
class RADGigastar : public Device {
|
||||||
public:
|
public:
|
||||||
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGigastar;
|
// Serial numbers start with GS
|
||||||
static constexpr const char* SERIAL_START = "GS";
|
// USB PID is 0x1204, standard driver is FTDI3
|
||||||
|
// Ethernet MAC allocation is 0x0F, standard driver is Raw
|
||||||
|
ICSNEO_FINDABLE_DEVICE(RADGigastar, DeviceType::RADGigastar, "GS");
|
||||||
|
|
||||||
size_t getEthernetActivationLineCount() const override { return 1; }
|
size_t getEthernetActivationLineCount() const override { return 1; }
|
||||||
|
|
||||||
|
bool getEthPhyRegControlSupported() const override { return true; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RADGigastar(neodevice_t neodevice) : Device(neodevice) {
|
RADGigastar(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||||
getWritableNeoDevice().type = DEVICE_TYPE;
|
initialize<RADGigastarSettings>(makeDriver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupPacketizer(Packetizer& packetizer) override {
|
void setupPacketizer(Packetizer& packetizer) override {
|
||||||
|
|
@ -35,6 +39,7 @@ protected:
|
||||||
void setupEncoder(Encoder& encoder) override {
|
void setupEncoder(Encoder& encoder) override {
|
||||||
Device::setupEncoder(encoder);
|
Device::setupEncoder(encoder);
|
||||||
encoder.supportCANFD = true;
|
encoder.supportCANFD = true;
|
||||||
|
encoder.supportEthPhy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||||
|
|
@ -81,8 +86,8 @@ protected:
|
||||||
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
|
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDeviceStatus(const std::shared_ptr<Message>& message) override {
|
void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
|
||||||
if(!message || message->data.size() < sizeof(radgigastar_status_t))
|
if(message->data.size() < sizeof(radgigastar_status_t))
|
||||||
return;
|
return;
|
||||||
std::lock_guard<std::mutex> lk(ioMutex);
|
std::lock_guard<std::mutex> lk(ioMutex);
|
||||||
const radgigastar_status_t* status = reinterpret_cast<const radgigastar_status_t*>(message->data.data());
|
const radgigastar_status_t* status = reinterpret_cast<const radgigastar_status_t*>(message->data.data());
|
||||||
|
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
#ifndef __RADGIGASTAR_ETH_H_
|
|
||||||
#define __RADGIGASTAR_ETH_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
|
|
||||||
#include "icsneo/device/tree/radgigastar/radgigastar.h"
|
|
||||||
#include "icsneo/platform/pcap.h"
|
|
||||||
|
|
||||||
namespace icsneo {
|
|
||||||
|
|
||||||
class RADGigastarETH : public RADGigastar {
|
|
||||||
public:
|
|
||||||
static constexpr const uint16_t PRODUCT_ID = 0x000F;
|
|
||||||
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
|
|
||||||
std::vector<std::shared_ptr<Device>> found;
|
|
||||||
|
|
||||||
for(auto& foundDev : pcapDevices) {
|
|
||||||
auto fakedev = std::shared_ptr<RADGigastarETH>(new RADGigastarETH({}));
|
|
||||||
for (auto& payload : foundDev.discoveryPackets)
|
|
||||||
fakedev->com->packetizer->input(payload);
|
|
||||||
for (auto& packet : fakedev->com->packetizer->output()) {
|
|
||||||
std::shared_ptr<Message> msg;
|
|
||||||
if (!fakedev->com->decoder->decode(msg, packet))
|
|
||||||
continue; // We failed to decode this packet
|
|
||||||
|
|
||||||
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
|
|
||||||
continue; // Not a message we care about
|
|
||||||
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
|
|
||||||
if(!sn)
|
|
||||||
continue; // Not a serial number message
|
|
||||||
|
|
||||||
if(sn->deviceSerial.length() < 2)
|
|
||||||
continue;
|
|
||||||
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
|
|
||||||
continue; // Not a RADGigastar
|
|
||||||
|
|
||||||
auto device = foundDev.device;
|
|
||||||
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
|
|
||||||
found.push_back(std::shared_ptr<RADGigastarETH>(new RADGigastarETH(std::move(device))));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RADGigastarETH(neodevice_t neodevice) : RADGigastar(neodevice) {
|
|
||||||
initialize<PCAP, RADGigastarSettings>();
|
|
||||||
productId = PRODUCT_ID;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue