mirror of
https://github.com/intrepidcs/libicsneo.git
synced 2026-09-24 09:49:47 +02:00
Compare commits
22
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06f6861130 | ||
|
|
219a5edbd8 | ||
|
|
05888e5c20 | ||
|
|
e37d939699 | ||
|
|
2a94b4566b | ||
|
|
4782e26bed | ||
|
|
3264a1ecbe | ||
|
|
1dfed4c9c4 | ||
|
|
a44952be13 | ||
|
|
75e9319c32 | ||
|
|
9df4aed19f | ||
|
|
d56e66afd3 | ||
|
|
26b52237e4 | ||
|
|
28ba94fa25 | ||
|
|
e56c714a0c | ||
|
|
58f53edea8 | ||
|
|
3d2d3cb43d | ||
|
|
bddbcfcf6d | ||
|
|
0497b361ef | ||
|
|
02f1b4592e | ||
|
|
4248c1a538 | ||
|
|
ec51393dfc |
@@ -171,6 +171,8 @@ test linux/ubuntu/2204/amd64/clang:
|
||||
paths:
|
||||
- /var/cache/dnf
|
||||
script:
|
||||
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
|
||||
- echo fastestmirror=True >>/etc/dnf/dnf.conf
|
||||
- dnf upgrade -y
|
||||
- dnf install -y g++ libpcap-devel cmake ninja-build libusb1-devel
|
||||
- sh ci/build-posix.sh
|
||||
@@ -188,6 +190,8 @@ test linux/ubuntu/2204/amd64/clang:
|
||||
paths:
|
||||
- /var/cache/dnf
|
||||
script:
|
||||
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
|
||||
- echo fastestmirror=True >>/etc/dnf/dnf.conf
|
||||
- dnf upgrade -y
|
||||
- dnf install -y libpcap-devel libusb1-devel
|
||||
- build/libicsneo-tests
|
||||
@@ -201,6 +205,8 @@ test linux/ubuntu/2204/amd64/clang:
|
||||
paths:
|
||||
- /var/cache/dnf
|
||||
script:
|
||||
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
|
||||
- echo fastestmirror=True >>/etc/dnf/dnf.conf
|
||||
- dnf upgrade -y
|
||||
- dnf install -y clang lld libpcap-devel cmake ninja-build libusb1-devel
|
||||
- CC=clang CXX=clang++ LDFLAGS=-fuse-ld=lld sh ci/build-posix.sh
|
||||
@@ -218,6 +224,8 @@ test linux/ubuntu/2204/amd64/clang:
|
||||
paths:
|
||||
- /var/cache/dnf
|
||||
script:
|
||||
- echo max_parallel_downloads=10 >>/etc/dnf/dnf.conf
|
||||
- echo fastestmirror=True >>/etc/dnf/dnf.conf
|
||||
- dnf upgrade -y
|
||||
- dnf install -y libpcap-devel libusb1-devel
|
||||
- build/libicsneo-tests
|
||||
@@ -248,3 +256,51 @@ test linux/fedora/37/amd64/clang:
|
||||
- build linux/fedora/37/amd64/clang
|
||||
needs:
|
||||
- build linux/fedora/37/amd64/clang
|
||||
|
||||
build linux/fedora/38/amd64/gcc:
|
||||
<<: *build_linux_fedora_gcc
|
||||
image: fedora:38
|
||||
|
||||
test linux/fedora/38/amd64/gcc:
|
||||
<<: *test_linux_fedora_gcc
|
||||
image: fedora:38
|
||||
dependencies:
|
||||
- build linux/fedora/38/amd64/gcc
|
||||
needs:
|
||||
- build linux/fedora/38/amd64/gcc
|
||||
|
||||
build linux/fedora/38/amd64/clang:
|
||||
<<: *build_linux_fedora_clang
|
||||
image: fedora:38
|
||||
|
||||
test linux/fedora/38/amd64/clang:
|
||||
<<: *test_linux_fedora_clang
|
||||
image: fedora:38
|
||||
dependencies:
|
||||
- build linux/fedora/38/amd64/clang
|
||||
needs:
|
||||
- build linux/fedora/38/amd64/clang
|
||||
|
||||
build linux/fedora/39/amd64/gcc:
|
||||
<<: *build_linux_fedora_gcc
|
||||
image: fedora:39
|
||||
|
||||
test linux/fedora/39/amd64/gcc:
|
||||
<<: *test_linux_fedora_gcc
|
||||
image: fedora:39
|
||||
dependencies:
|
||||
- build linux/fedora/39/amd64/gcc
|
||||
needs:
|
||||
- build linux/fedora/39/amd64/gcc
|
||||
|
||||
build linux/fedora/39/amd64/clang:
|
||||
<<: *build_linux_fedora_clang
|
||||
image: fedora:39
|
||||
|
||||
test linux/fedora/39/amd64/clang:
|
||||
<<: *test_linux_fedora_clang
|
||||
image: fedora:39
|
||||
dependencies:
|
||||
- build linux/fedora/39/amd64/clang
|
||||
needs:
|
||||
- build linux/fedora/39/amd64/clang
|
||||
|
||||
+23
-23
@@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.12)
|
||||
project(libicsneo VERSION 0.3.0)
|
||||
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
if(POLICY CMP0135)
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
|
||||
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
|
||||
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
|
||||
@@ -18,7 +21,6 @@ set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to
|
||||
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_ANDROIDUSB "Enable devices which communicate over USB CDC ACM on Android" ON)
|
||||
option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX" ON)
|
||||
option(LIBICSNEO_ENABLE_TCP "Enable devices which communicate over TCP" OFF)
|
||||
option(LIBICSNEO_ENABLE_FTD3XX "Enable devices which communicate over USB FTD3XX" ON)
|
||||
@@ -46,6 +48,8 @@ else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# doxygen
|
||||
find_package(Doxygen)
|
||||
if(DOXYGEN_FOUND)
|
||||
@@ -118,12 +122,6 @@ if(WIN32)
|
||||
platform/windows/vcp.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
elseif(LIBICSNEO_ENABLE_ANDROIDUSB)
|
||||
list(APPEND PLATFORM_SRC
|
||||
platform/android/androidusb.cpp
|
||||
)
|
||||
|
||||
else() # Darwin or Linux
|
||||
set(PLATFORM_SRC)
|
||||
|
||||
@@ -168,7 +166,6 @@ else() # Darwin or Linux
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(LIBICSNEO_ENABLE_FTD3XX)
|
||||
if(NOT FTD3XX_ROOT) # allow system override
|
||||
include(FetchContent)
|
||||
@@ -281,6 +278,22 @@ set(SRC_FILES
|
||||
disk/plasiondiskreaddriver.cpp
|
||||
disk/extextractordiskreaddriver.cpp
|
||||
disk/fat.cpp
|
||||
disk/vsa/vsa.cpp
|
||||
disk/vsa/vsa02.cpp
|
||||
disk/vsa/vsa03.cpp
|
||||
disk/vsa/vsa04.cpp
|
||||
disk/vsa/vsa05.cpp
|
||||
disk/vsa/vsa06.cpp
|
||||
disk/vsa/vsa07.cpp
|
||||
disk/vsa/vsa08.cpp
|
||||
disk/vsa/vsa09.cpp
|
||||
disk/vsa/vsa0b.cpp
|
||||
disk/vsa/vsa0c.cpp
|
||||
disk/vsa/vsa0d.cpp
|
||||
disk/vsa/vsa0e.cpp
|
||||
disk/vsa/vsa0f.cpp
|
||||
disk/vsa/vsa6a.cpp
|
||||
disk/vsa/vsaparser.cpp
|
||||
${PLATFORM_SRC}
|
||||
)
|
||||
|
||||
@@ -341,6 +354,7 @@ target_include_directories(icsneocpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${LIBICSNEO_EXTENSION_INCLUDE_PATHS}
|
||||
)
|
||||
target_link_libraries(icsneocpp PUBLIC Threads::Threads)
|
||||
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)
|
||||
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
|
||||
@@ -364,18 +378,10 @@ endif()
|
||||
if(LIBICSNEO_ENABLE_TCP)
|
||||
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_TCP)
|
||||
if(WIN32)
|
||||
target_link_libraries(icsneocpp PRIVATE ws2_32)
|
||||
target_link_libraries(icsneocpp PRIVATE ws2_32 iphlpapi)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_ENABLE_ANDROIDUSB)
|
||||
add_library(libusb SHARED IMPORTED)
|
||||
set_target_properties(libusb PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/third-party/libusb/android/libs/${ANDROID_ABI}/libusb1.0.so)
|
||||
target_include_directories(icsneocpp PRIVATE third-party/libusb/libusb)
|
||||
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_ANDROIDUSB)
|
||||
target_link_libraries(icsneocpp PRIVATE android log libusb)
|
||||
endif()
|
||||
|
||||
# fatfs
|
||||
add_subdirectory(third-party/fatfs)
|
||||
set_property(TARGET fatfs PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
@@ -395,7 +401,6 @@ if(LIBICSNEO_ENABLE_FTDI)
|
||||
add_subdirectory(third-party/libftdi)
|
||||
target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
|
||||
|
||||
find_package(Threads)
|
||||
set_property(TARGET ftdi1-static PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_link_libraries(icsneocpp PUBLIC ftdi1-static)
|
||||
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||
@@ -430,11 +435,6 @@ if(LIBICSNEO_BUILD_ICSNEOC)
|
||||
)
|
||||
target_link_libraries(icsneoc PRIVATE icsneocpp)
|
||||
target_compile_features(icsneoc PRIVATE cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
|
||||
if(LIBICSNEO_ENABLE_ANDROIDUSB)
|
||||
target_link_libraries(icsneoc PRIVATE android log)
|
||||
target_include_directories(icsneoc PRIVATE third-party/libusb/libusb)
|
||||
target_compile_definitions(icsneoc PRIVATE ICSNEO_ENABLE_ANDROIDUSB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_ICSNEOC_STATIC)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2018-2023 Intrepid Control Systems, Inc.
|
||||
Copyright 2018-2024 Intrepid Control Systems, Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
|
||||
+18
-14
@@ -111,15 +111,11 @@ bool icsneo_isValidNeoDevice(const neodevice_t* device) {
|
||||
}
|
||||
|
||||
bool icsneo_openDevice(const neodevice_t* device) {
|
||||
if(!icsneo_isValidNeoDevice(device)) {
|
||||
//todo error
|
||||
if(!icsneo_isValidNeoDevice(device))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!device->device->open()) {
|
||||
//todo error
|
||||
if(!device->device->open())
|
||||
return false;
|
||||
}
|
||||
|
||||
// We connected successfully, move the device to connected devices
|
||||
std::vector<std::vector<std::shared_ptr<Device>>::iterator> itemsToMove;
|
||||
@@ -148,8 +144,17 @@ bool icsneo_closeDevice(const neodevice_t* device) {
|
||||
if((*it).get() == device->device)
|
||||
itemsToDelete.push_back(it);
|
||||
}
|
||||
for(auto it : itemsToDelete)
|
||||
for(auto it : itemsToDelete) {
|
||||
// Move it back into connectable devices so we can open it again.
|
||||
// Without this we will be unable to use/reopen the device due to
|
||||
// icsneo_isValidNeoDevice / icsneo_openDevice checks against this
|
||||
// container. Since its closed we are in a connectable state again.
|
||||
// Notice: When we search again this will be cleaned up by
|
||||
// icsneo_freeUnconnectedDevices()
|
||||
connectableFoundDevices.push_back(*it);
|
||||
// Remove it from the connected devices as we are no longer connected.
|
||||
connectedDevices.erase(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -224,6 +229,7 @@ bool icsneo_getMessages(const neodevice_t* device, neomessage_t* messages, size_
|
||||
return false;
|
||||
|
||||
*items = storage.size();
|
||||
|
||||
for(size_t i = 0; i < *items; i++) {
|
||||
// For each message, copy into neomessage_t buffer given
|
||||
messages[i] = CreateNeoMessage(storage[i]);
|
||||
@@ -744,12 +750,10 @@ int icsneo_getDeviceStatus(const neodevice_t* device, void* status, size_t* size
|
||||
|
||||
return true;
|
||||
}
|
||||
#ifdef ICSNEO_ENABLE_ANDROIDUSB
|
||||
bool icsneo_addSysFileDescriptor(int sysFd) {
|
||||
return icsneo::ANDROIDUSB::addSystemFD(sysFd);
|
||||
|
||||
bool icsneo_isOnlineSupported(const neodevice_t* device) {
|
||||
if(!icsneo_isValidNeoDevice(device))
|
||||
return false;
|
||||
|
||||
return device->device->isOnlineSupported();
|
||||
}
|
||||
bool icsneo_removeSysFileDescriptor(int sysFd) {
|
||||
return icsneo::ANDROIDUSB::removeSystemFD(sysFd);
|
||||
}
|
||||
#endif
|
||||
@@ -29,7 +29,7 @@ BEGIN
|
||||
VALUE "FileDescription", "Intrepid Control Systems Open Device Communication C API"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "InternalName", "icsneoc.dll"
|
||||
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2023"
|
||||
VALUE "LegalCopyright", "Intrepid Control Systems, Inc. (C) 2018-2024"
|
||||
VALUE "OriginalFilename", "icsneoc.dll"
|
||||
VALUE "ProductName", "libicsneo"
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
|
||||
@@ -72,6 +72,7 @@ static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too
|
||||
static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present.";
|
||||
static constexpr const char* TIMEOUT = "The timeout was reached.";
|
||||
static constexpr const char* WIVI_NOT_SUPPORTED = "Wireless neoVI functions are not supported on this device.";
|
||||
static constexpr const char* RESTRICTED_ENTRY_FLAG = "Attempted to set a restricted flag in a Root Directory entry.";
|
||||
|
||||
// Device Errors
|
||||
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
|
||||
@@ -116,6 +117,8 @@ static constexpr const char* A2B_MESSAGE_INCOMPLETE_FRAME = "At least one of the
|
||||
static constexpr const char* COREMINI_UPLOAD_VERSION_MISMATCH = "The version of the coremini engine on the device and the script uploaded are not the same.";
|
||||
static constexpr const char* DISK_NOT_CONNECTED = "The program tried to access a disk that is not connected.";
|
||||
static constexpr const char* UNEXPECTED_RESPONSE = "Received an unexpected or invalid response from the device.";
|
||||
static constexpr const char* LIN_SETTINGS_NOT_AVAILABLE = "LIN settings are not available for this device.";
|
||||
static constexpr const char* MODE_NOT_FOUND = "The mode was not found.";
|
||||
|
||||
// Transport Errors
|
||||
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
|
||||
@@ -169,6 +172,15 @@ static constexpr const char* FT_DEVICE_NOT_CONNECTED = "FTD3XX device not connec
|
||||
static constexpr const char* FT_INCORRECT_DEVICE_PATH = "Incorrect FTD3XX device path.";
|
||||
static constexpr const char* FT_OTHER_ERROR = "Other FTD3XX error.";
|
||||
|
||||
// VSA
|
||||
static constexpr const char* VSA_BUFFER_CORRUPTED = "VSA data in record buffer is corrupted.";
|
||||
static constexpr const char* VSA_TIMESTAMP_NOT_FOUND = "Unable to find a VSA record with a valid timestamp.";
|
||||
static constexpr const char* VSA_BUFFER_FORMAT_ERROR = "VSA record buffer is formatted incorrectly.";
|
||||
static constexpr const char* VSA_MAX_READ_ATTEMPTS_REACHED = "Reached max attempts to read VSA records before exit.";
|
||||
static constexpr const char* VSA_BYTE_PARSE_FAILURE = "Failure to parse record bytes from VSA buffer.";
|
||||
static constexpr const char* VSA_EXTENDED_MESSAGE_ERROR = "Failure to parse extended message record sequence";
|
||||
static constexpr const char* VSA_OTHER_ERROR = "Unknown error in VSA read API.";
|
||||
|
||||
static constexpr const char* TOO_MANY_EVENTS = "Too many events have occurred. The list has been truncated.";
|
||||
static constexpr const char* UNKNOWN = "An unknown internal error occurred.";
|
||||
static constexpr const char* INVALID = "An invalid internal error occurred.";
|
||||
@@ -207,6 +219,8 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||
return TIMEOUT;
|
||||
case Type::WiVINotSupported:
|
||||
return WIVI_NOT_SUPPORTED;
|
||||
case Type::RestrictedEntryFlag:
|
||||
return RESTRICTED_ENTRY_FLAG;
|
||||
|
||||
// Device Errors
|
||||
case Type::PollingMessageOverflow:
|
||||
@@ -293,6 +307,10 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||
return DISK_NOT_CONNECTED;
|
||||
case Type::UnexpectedResponse:
|
||||
return UNEXPECTED_RESPONSE;
|
||||
case Type::LINSettingsNotAvailable:
|
||||
return LIN_SETTINGS_NOT_AVAILABLE;
|
||||
case Type::ModeNotFound:
|
||||
return MODE_NOT_FOUND;
|
||||
// Transport Errors
|
||||
case Type::FailedToRead:
|
||||
return FAILED_TO_READ;
|
||||
@@ -393,6 +411,22 @@ const char* APIEvent::DescriptionForType(Type type) {
|
||||
case Type::FTOtherError:
|
||||
return FT_OTHER_ERROR;
|
||||
|
||||
// VSA
|
||||
case Type::VSABufferCorrupted:
|
||||
return VSA_BUFFER_CORRUPTED;
|
||||
case Type::VSATimestampNotFound:
|
||||
return VSA_TIMESTAMP_NOT_FOUND;
|
||||
case Type::VSABufferFormatError:
|
||||
return VSA_BUFFER_FORMAT_ERROR;
|
||||
case Type::VSAMaxReadAttemptsReached:
|
||||
return VSA_MAX_READ_ATTEMPTS_REACHED;
|
||||
case Type::VSAByteParseFailure:
|
||||
return VSA_BYTE_PARSE_FAILURE;
|
||||
case Type::VSAExtendedMessageError:
|
||||
return VSA_EXTENDED_MESSAGE_ERROR;
|
||||
case Type::VSAOtherError:
|
||||
return VSA_OTHER_ERROR;
|
||||
|
||||
// Other Errors
|
||||
case Type::TooManyEvents:
|
||||
return TOO_MANY_EVENTS;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "icsneo/icsneocpp.h"
|
||||
#include "icsneo/device/devicefinder.h"
|
||||
#include <jni.h>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#include <Tchar.h>
|
||||
|
||||
//Basic Functions
|
||||
FINDNEODEVICES icsneoFindNeoDevices;
|
||||
OPENNEODEVICE icsneoOpenNeoDevice;
|
||||
OPENDEVICE icsneoOpenDevice;
|
||||
CLOSEPORT icsneoClosePort;
|
||||
FREEOBJECT icsneoFreeObject;
|
||||
@@ -134,10 +132,6 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
|
||||
if((hAPIDLL = LoadLibrary(_T("icsneo40.dll"))) == NULL)
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
icsneoFindNeoDevices = (FINDNEODEVICES) GetProcAddress(hAPIDLL, "icsneoFindNeoDevices");
|
||||
icsneoOpenNeoDevice = (OPENNEODEVICE) GetProcAddress(hAPIDLL, "icsneoOpenNeoDevice");
|
||||
icsneoOpenDevice = (OPENDEVICE) GetProcAddress(hAPIDLL, "icsneoOpenDevice");
|
||||
icsneoClosePort = (CLOSEPORT) GetProcAddress(hAPIDLL, "icsneoClosePort");
|
||||
icsneoFreeObject = (FREEOBJECT) GetProcAddress(hAPIDLL, "icsneoFreeObject");
|
||||
@@ -206,7 +200,7 @@ bool LoadDLLAPI(HINSTANCE &hAPIDLL)
|
||||
|
||||
icsneoEnableDOIPLine = (ENABLEDOIPACTIVATIONLINE)GetProcAddress(hAPIDLL, "icsneoEnableDOIPLine");
|
||||
|
||||
if(!icsneoFindNeoDevices || !icsneoOpenNeoDevice || !icsneoOpenDevice || !icsneoClosePort || !icsneoFreeObject ||
|
||||
if(!icsneoOpenDevice || !icsneoClosePort || !icsneoFreeObject ||
|
||||
!icsneoTxMessages || !icsneoGetMessages || !icsneoWaitForRxMessagesWithTimeOut ||
|
||||
!icsneoGetTimeStampForMsg || !icsneoEnableNetworkRXQueue || !icsneoGetISO15765Status || !icsneoTxMessagesEx ||
|
||||
!icsneoSetISO15765RxParameters || !icsneoGetConfiguration || !icsneoSendConfiguration ||
|
||||
|
||||
@@ -114,8 +114,6 @@ typedef int (__stdcall *SCRIPTWRITEISO15765TXMESSAGE)(void * hObject, unsigned
|
||||
|
||||
|
||||
//Basic Functions
|
||||
extern FINDNEODEVICES icsneoFindNeoDevices;
|
||||
extern OPENNEODEVICE icsneoOpenNeoDevice;
|
||||
extern OPENDEVICE icsneoOpenDevice;
|
||||
extern CLOSEPORT icsneoClosePort;
|
||||
extern FREEOBJECT icsneoFreeObject;
|
||||
|
||||
+107
-136
@@ -14,7 +14,6 @@
|
||||
#include "icsneo/communication/network.h"
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include <cstring>
|
||||
#include <climits>
|
||||
|
||||
@@ -27,6 +26,7 @@ using namespace icsneo;
|
||||
|
||||
typedef uint64_t legacymaphandle_t;
|
||||
static std::map<legacymaphandle_t, neodevice_t> neodevices;
|
||||
static std::map<neodevice_t*, NeoDeviceEx*> openneodevices;
|
||||
|
||||
static const std::map<size_t, size_t> mp_netIDToVnetOffSet = {
|
||||
{NETID_HSCAN, 1},
|
||||
@@ -52,18 +52,6 @@ static const std::map<size_t, size_t> mp_HWnetIDToCMnetID = {
|
||||
|
||||
static unsigned long vnet_table[] = {0, PLASMA_SLAVE1_OFFSET, PLASMA_SLAVE2_OFFSET};
|
||||
|
||||
static NeoDevice OldNeoDeviceFromNew(const neodevice_t* newnd)
|
||||
{
|
||||
NeoDevice oldnd = {0};
|
||||
oldnd.DeviceType = newnd->type;
|
||||
oldnd.SerialNumber = icsneo_serialStringToNum(newnd->serial);
|
||||
oldnd.NumberOfClients = 0;
|
||||
oldnd.MaxAllowedClients = 1;
|
||||
static_assert(sizeof(neodevice_handle_t) == sizeof(oldnd.Handle),
|
||||
"neodevice_handle_t size must be sizeof(int) for compatibility reasons");
|
||||
oldnd.Handle = newnd->handle;
|
||||
return oldnd;
|
||||
}
|
||||
|
||||
static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t& newmsg, icsSpyMessage& oldmsg)
|
||||
{
|
||||
@@ -318,109 +306,81 @@ static inline size_t GetVnetAgnosticNetid(size_t fullNetid)
|
||||
int LegacyDLLExport icsneoFindDevices(NeoDeviceEx* devs, int* devCount, unsigned int* devTypes, unsigned int devTypeCount,
|
||||
POptionsFindNeoEx* POptionsFindNeoEx, unsigned int* zero)
|
||||
{
|
||||
if (!devs || !devCount)
|
||||
// Match the legacy API maximum, this derives from the maximum COM Port on old windows versions.
|
||||
constexpr int MAX_NEO_DEVICES = 255;
|
||||
|
||||
// Validate arguments
|
||||
if (!devCount && *devCount < 0) {
|
||||
return 0;
|
||||
|
||||
if (*devCount < 0 || *devCount > 255)
|
||||
return 0;
|
||||
|
||||
// Find the devices without filtering by the device type
|
||||
// We allow this to find more than the requested number,
|
||||
// as we may filter out some devices.
|
||||
constexpr const size_t MAX_DEVICES = 255;
|
||||
NeoDevice foundDevices[MAX_DEVICES];
|
||||
int NumDevices = MAX_DEVICES;
|
||||
|
||||
int filteredDeviceCount = 0;
|
||||
|
||||
if (!icsneoFindNeoDevices(0, foundDevices, &NumDevices))
|
||||
return 0;
|
||||
|
||||
for (auto i = 0; i < NumDevices; i++)
|
||||
{
|
||||
// Check if the next device would overrun the user's buffer
|
||||
// We check this up here since the documentation allows zero
|
||||
// to be specified.
|
||||
if (filteredDeviceCount >= *devCount)
|
||||
break;
|
||||
|
||||
if (devTypes && devTypeCount)
|
||||
{
|
||||
for (unsigned int j = 0; j < devTypeCount; j++)
|
||||
{
|
||||
if (foundDevices[i].DeviceType == devTypes[j])
|
||||
{
|
||||
devs[filteredDeviceCount++].neoDevice = foundDevices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// return the size only if devs is NULL.
|
||||
if (!devs)
|
||||
{
|
||||
devs[filteredDeviceCount++].neoDevice = foundDevices[i];
|
||||
}
|
||||
}
|
||||
|
||||
*devCount = filteredDeviceCount;
|
||||
return 1; // If the function succeeds but no devices are found 1 will still be returned and devCount will equal 0
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoFindNeoDevices(unsigned long DeviceTypes, NeoDevice* pNeoDevice, int* pNumDevices)
|
||||
{
|
||||
constexpr size_t MAX_DEVICES = 255;
|
||||
size_t count = MAX_DEVICES;
|
||||
|
||||
if (pNumDevices == nullptr)
|
||||
return 0;
|
||||
|
||||
if (pNeoDevice == nullptr)
|
||||
{
|
||||
icsneo_findAllDevices(nullptr, &count);
|
||||
*pNumDevices = (int)count;
|
||||
icsneo_findAllDevices(nullptr, (size_t*)devCount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t bufferSize = (size_t)*pNumDevices;
|
||||
if (*pNumDevices < 0 || bufferSize > MAX_DEVICES)
|
||||
return 0;
|
||||
|
||||
neodevice_t devices[MAX_DEVICES];
|
||||
icsneo_findAllDevices(devices, &count);
|
||||
if (bufferSize < count)
|
||||
count = bufferSize;
|
||||
*pNumDevices = (int)count;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
pNeoDevice[i] = OldNeoDeviceFromNew(&devices[i]); // Write out into user memory
|
||||
neodevices[uint64_t(devices[i].handle) << 32 | icsneo_serialStringToNum(devices[i].serial)] = devices[i]; // Fill the look up table
|
||||
// shrink the number of devices allowed to find
|
||||
if (*devCount > MAX_NEO_DEVICES) {
|
||||
*devCount = MAX_NEO_DEVICES;
|
||||
}
|
||||
// Find all the neodevice_t devices
|
||||
std::vector<neodevice_t> neoDevices(*devCount);
|
||||
auto neoDevicesSize = neoDevices.size();
|
||||
icsneo_findAllDevices(neoDevices.data(), &neoDevicesSize);
|
||||
neoDevices.resize(neoDevicesSize);
|
||||
// Filter out the devices if needed
|
||||
// No filtering needed
|
||||
if (devTypes && devTypeCount > 0) {
|
||||
neoDevices.erase(
|
||||
std::remove_if(
|
||||
neoDevices.begin(),
|
||||
neoDevices.end(),
|
||||
[&](const auto& iter) {
|
||||
for (unsigned int i=0; i < devTypeCount; ++i) {
|
||||
if (iter.type == devTypes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
),
|
||||
neoDevices.end()
|
||||
);
|
||||
}
|
||||
// Create a NeoDeviceEx From a neodevice_t
|
||||
auto _createNeoDeviceExFrom = [](const neodevice_t* neoDevice) -> NeoDeviceEx {
|
||||
NeoDeviceEx nde = {};
|
||||
nde.neoDevice.DeviceType = neoDevice->type;
|
||||
nde.neoDevice.SerialNumber = icsneo_serialStringToNum(neoDevice->serial);
|
||||
nde.neoDevice.NumberOfClients = 0;
|
||||
nde.neoDevice.MaxAllowedClients = 1;
|
||||
static_assert(sizeof(neodevice_handle_t) == sizeof(nde.neoDevice.Handle),
|
||||
"neodevice_handle_t size must be sizeof(int) for compatibility reasons");
|
||||
nde.neoDevice.Handle = neoDevice->handle;
|
||||
return nde;
|
||||
};
|
||||
|
||||
// Create the NeoDeviceEx from the neodevice_t
|
||||
auto i = 0;
|
||||
for (const auto& neoDevice : neoDevices) {
|
||||
// Fill the look up table
|
||||
neodevices[uint64_t(neoDevice.handle) << 32 | icsneo_serialStringToNum(neoDevice.serial)] = neoDevice;
|
||||
// Create the NeoDeviceEx
|
||||
devs[i] = _createNeoDeviceExFrom(&neoDevice);
|
||||
NeoDeviceEx* nde = &devs[i];
|
||||
++i;
|
||||
// Lookup the open NeoDeviceEx devices and match the NumberOfClients value if available.
|
||||
for (auto& [neo_device, open_nde]: openneodevices) {
|
||||
// SerialNumber should always be unique so lets compare against that.
|
||||
if (nde->neoDevice.SerialNumber == open_nde->neoDevice.SerialNumber) {
|
||||
nde->neoDevice.NumberOfClients = open_nde->neoDevice.NumberOfClients;
|
||||
}
|
||||
}
|
||||
}
|
||||
*devCount = (int)neoDevices.size();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoOpenNeoDevice(NeoDevice* pNeoDevice, void** hObject, unsigned char* bNetworkIDs, int bConfigRead, int bSyncToPC)
|
||||
{
|
||||
if (pNeoDevice == nullptr || hObject == nullptr)
|
||||
return false;
|
||||
|
||||
neodevice_t *device;
|
||||
try
|
||||
{
|
||||
device = &neodevices.at(uint64_t(pNeoDevice->Handle) << 32 | pNeoDevice->SerialNumber);
|
||||
}
|
||||
catch (const std::out_of_range&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*hObject = device;
|
||||
if (!icsneo_openDevice(device))
|
||||
return false;
|
||||
|
||||
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoOpenDevice(
|
||||
NeoDeviceEx* pNeoDeviceEx,
|
||||
void** hObject,
|
||||
@@ -443,19 +403,50 @@ int LegacyDLLExport icsneoOpenDevice(
|
||||
return false;
|
||||
}
|
||||
|
||||
*hObject = device;
|
||||
if(!icsneo_openDevice(device))
|
||||
if (pNeoDeviceEx->neoDevice.NumberOfClients >= pNeoDeviceEx->neoDevice.MaxAllowedClients) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
|
||||
*hObject = device;
|
||||
if(!icsneo_openDevice(device)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (icsneo_isOnlineSupported(device)) {
|
||||
if (!icsneo_setPollingMessageLimit(device, 20000)) {
|
||||
icsneo_closeDevice(device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!icsneo_enableMessagePolling(device)) {
|
||||
icsneo_closeDevice(device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!icsneo_goOnline(device)) {
|
||||
icsneo_closeDevice(device);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pNeoDeviceEx->neoDevice.NumberOfClients = 1;
|
||||
// Add the open NeoDevice to the container so we can decrement NumberOfClients on close
|
||||
openneodevices[device] = pNeoDeviceEx;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoClosePort(void* hObject, int* pNumberOfErrors)
|
||||
{
|
||||
if (!icsneoValidateHObject(hObject))
|
||||
return false;
|
||||
if (pNumberOfErrors) {
|
||||
*pNumberOfErrors = 0;
|
||||
}
|
||||
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
|
||||
|
||||
if (openneodevices.find(device) != openneodevices.end()) {
|
||||
openneodevices[device]->neoDevice.NumberOfClients -= 1;
|
||||
openneodevices.erase(device);
|
||||
}
|
||||
return icsneo_closeDevice(device);
|
||||
}
|
||||
|
||||
@@ -991,20 +982,7 @@ int LegacyDLLExport icsneoScriptWriteAppSignal(void* hObject, unsigned int iInde
|
||||
return false;
|
||||
}
|
||||
|
||||
//Deprecated (but still suppored in the DLL)
|
||||
int LegacyDLLExport icsneoOpenPortEx(void* lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB,
|
||||
int lIPAddressLSBOrBaudRate, int bConfigRead, unsigned char* bNetworkID, int* hObject)
|
||||
{
|
||||
// TODO Implement
|
||||
return false;
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoOpenPort(int lPortNumber, int lPortType, int lDriverType, unsigned char *bNetworkID,
|
||||
unsigned char* bSCPIDs, int* hObject)
|
||||
{
|
||||
// TODO Implement
|
||||
return false;
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoEnableNetworkCom(void* hObject, int Enable)
|
||||
{
|
||||
@@ -1018,19 +996,6 @@ int LegacyDLLExport icsneoEnableNetworkCom(void* hObject, int Enable)
|
||||
return icsneo_goOffline(device);
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoFindAllCOMDevices(int lDriverType, int lGetSerialNumbers, int lStopAtFirst, int lUSBCommOnly,
|
||||
int* p_lDeviceTypes, int* p_lComPorts, int* p_lSerialNumbers, int* lNumDevices)
|
||||
{
|
||||
// TODO Implement
|
||||
return false;
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoOpenNeoDeviceByChannels(NeoDevice* pNeoDevice, void** hObject, unsigned char* uChannels, int iSize,
|
||||
int bConfigRead, int iOptions)
|
||||
{
|
||||
// TODO Implement
|
||||
return false;
|
||||
}
|
||||
|
||||
int LegacyDLLExport icsneoGetVCAN4Settings(void* hObject, SVCAN4Settings* pSettings, int iNumBytes)
|
||||
{
|
||||
@@ -1115,6 +1080,12 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
|
||||
case NEODEVICE_RED2:
|
||||
*pDeviceSettingsType = DeviceRed2SettingsType;
|
||||
break;
|
||||
case NEODEVICE_FIRE3:
|
||||
*pDeviceSettingsType = DeviceFire3SettingsType;
|
||||
break;
|
||||
case NEODEVICE_FIRE3_FLEXRAY:
|
||||
*pDeviceSettingsType = DeviceFire3FlexraySettingsType;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
|
||||
|
||||
A2BMessage& msg = *static_cast<A2BMessage*>(result.get());
|
||||
msg.network = packet->network;
|
||||
msg.timestamp *= timestampResolution;
|
||||
return true;
|
||||
}
|
||||
case Network::Type::LIN: {
|
||||
|
||||
@@ -4,20 +4,18 @@
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
const size_t HardwareA2BPacket::coreMiniMessageHeaderSize = 28;
|
||||
const size_t HardwareA2BPacket::a2bMessageMaxLength = (size_t)HardwareA2BPacket::coreMiniMessageHeaderSize + 1024;
|
||||
const size_t HardwareA2BPacket::a2bHeaderSize = 6;
|
||||
const size_t HardwareA2BPacket::a2bMessageMaxLength = sizeof(HardwareA2BPacket) + 1024;
|
||||
|
||||
std::shared_ptr<Message> HardwareA2BPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
|
||||
|
||||
if(bytestream.size() < coreMiniMessageHeaderSize)
|
||||
if(bytestream.size() < sizeof(HardwareA2BPacket))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const HardwareA2BPacket* data = (const HardwareA2BPacket*)bytestream.data();
|
||||
|
||||
size_t totalPackedLength = static_cast<size_t>(bytestream.size()) - static_cast<size_t>(coreMiniMessageHeaderSize); // First 28 bytes are message header.
|
||||
size_t totalPackedLength = static_cast<size_t>(bytestream.size()) - sizeof(HardwareA2BPacket); // First 28 bytes are message header.
|
||||
|
||||
std::shared_ptr<A2BMessage> msg = std::make_shared<A2BMessage>(
|
||||
(uint8_t)data->header.channelNum,
|
||||
@@ -30,7 +28,8 @@ std::shared_ptr<Message> HardwareA2BPacket::DecodeToMessage(const std::vector<ui
|
||||
msg->setErrIndicatorBit(data->header.errIndicator);
|
||||
msg->setSyncFrameBit(data->header.syncFrame);
|
||||
msg->setRFU2(data->header.rfu2);
|
||||
msg->setAudioBuffer(bytestream.begin() + coreMiniMessageHeaderSize, bytestream.end());
|
||||
msg->timestamp = data->timestamp.TS;
|
||||
msg->setAudioBuffer(bytestream.begin() + sizeof(HardwareA2BPacket), bytestream.end());
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ std::shared_ptr<SupportedFeaturesMessage> SupportedFeaturesPacket::DecodeToMessa
|
||||
}
|
||||
// Get a reference to the payload to fully validate the length
|
||||
const auto& response = *reinterpret_cast<const SupportedFeaturesResponse*>(bytes.data());
|
||||
if(response.cmdVersion != SupportedFeaturesCommandVersion) {
|
||||
return msg;
|
||||
}
|
||||
// Expected size is the header, cmdVersion and numValidBits fields, plus the number of 32-bit bitfields in the response based on numValidBits
|
||||
auto expectedSize = sizeof(ExtendedResponseMessage::ResponseHeader) + 4 + ((response.numValidBits + 31) / 32) * 4;
|
||||
// If the response is malformed (too small), return an empty message
|
||||
|
||||
+1192
-41
File diff suppressed because it is too large
Load Diff
+18
-10
@@ -15,10 +15,6 @@
|
||||
#include "icsneo/platform/cdcacm.h"
|
||||
#endif
|
||||
|
||||
#ifdef ICSNEO_ENABLE_ANDROIDUSB
|
||||
#include "icsneo/platform/android/androidusb.h"
|
||||
#endif
|
||||
|
||||
#ifdef ICSNEO_ENABLE_FTDI
|
||||
#include "icsneo/platform/ftdi.h"
|
||||
#endif
|
||||
@@ -51,6 +47,18 @@ static void makeIfPIDMatches(const FoundDevice& dev, std::vector<std::shared_ptr
|
||||
into.push_back(std::make_shared<T>(dev));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void makeIfSerialRangeMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
|
||||
// Relies on the subclass to have
|
||||
// `static constexpr uint32_t SERIAL_RANGE_LOW = 0x12345678`
|
||||
// `static constexpr uint32_t SERIAL_RANGE_HIGH = 0x12345678`
|
||||
// and also a public constructor `T(const FoundDevice& dev)`
|
||||
// Use macro ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE() to create these
|
||||
uint32_t serialNum = Device::SerialStringToNum(dev.serial);
|
||||
if(serialNum >= Device::SerialStringToNum(T::SERIAL_RANGE_LOW) && serialNum <= Device::SerialStringToNum(T::SERIAL_RANGE_HIGH))
|
||||
into.push_back(std::make_shared<T>(dev));
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
||||
static std::vector<FoundDevice> newDriverFoundDevices;
|
||||
newDriverFoundDevices.clear();
|
||||
@@ -71,10 +79,6 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
||||
CDCACM::Find(newDriverFoundDevices);
|
||||
#endif
|
||||
|
||||
#ifdef ICSNEO_ENABLE_ANDROIDUSB
|
||||
ANDROIDUSB::Find(newDriverFoundDevices);
|
||||
#endif
|
||||
|
||||
#ifdef ICSNEO_ENABLE_FTDI
|
||||
FTDI::Find(newDriverFoundDevices);
|
||||
#endif
|
||||
@@ -166,7 +170,11 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
|
||||
#endif
|
||||
|
||||
#ifdef __RADCOMET_H_
|
||||
makeIfSerialMatches<RADCOMET>(dev, newFoundDevices);
|
||||
makeIfSerialRangeMatches<RADComet>(dev, newFoundDevices);
|
||||
#endif
|
||||
|
||||
#ifdef __RADCOMET2_H_
|
||||
makeIfSerialRangeMatches<RADComet2>(dev, newFoundDevices);
|
||||
#endif
|
||||
|
||||
#ifdef __RADEPSILON_H_
|
||||
@@ -305,7 +313,7 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
|
||||
#endif
|
||||
|
||||
#ifdef __RADCOMET_H_
|
||||
RADCOMET::DEVICE_TYPE,
|
||||
RADComet::DEVICE_TYPE,
|
||||
#endif
|
||||
|
||||
#ifdef __RADEPSILON_H_
|
||||
|
||||
@@ -128,6 +128,37 @@ int64_t IDeviceSettings::GetBaudrateValueForEnum(CANBaudrate enumValue) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IDeviceSettings::ValidateLINBaudrate(int64_t baudrate) {
|
||||
switch(baudrate) {
|
||||
case 4800:
|
||||
// fallthrough
|
||||
case 9600:
|
||||
// fallthrough
|
||||
case 10400:
|
||||
// fallthrough
|
||||
case 10417:
|
||||
// fallthrough
|
||||
case 10504:
|
||||
// fallthrough
|
||||
case 10593:
|
||||
// fallthrough
|
||||
case 10684:
|
||||
// fallthrough
|
||||
case 10776:
|
||||
// fallthrough
|
||||
case 10870:
|
||||
// fallthrough
|
||||
case 10965:
|
||||
// fallthrough
|
||||
case 11062:
|
||||
// fallthrough
|
||||
case 19200:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDeviceSettings::refresh(bool ignoreChecksum) {
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
@@ -414,6 +445,15 @@ int64_t IDeviceSettings::getBaudrateFor(Network net) const {
|
||||
}
|
||||
return baudrate;
|
||||
}
|
||||
case Network::Type::LIN: {
|
||||
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cfg->Baudrate;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return -1;
|
||||
@@ -493,6 +533,21 @@ bool IDeviceSettings::setBaudrateFor(Network net, int64_t baudrate) {
|
||||
cfg->SetBaudrate = AUTO; // Device will use the baudrate value to set the TQ values
|
||||
return true;
|
||||
}
|
||||
case Network::Type::LIN: {
|
||||
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid = ValidateLINBaudrate(baudrate);
|
||||
if(!valid) {
|
||||
report(APIEvent::Type::BaudrateNotFound, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
cfg->Baudrate = (uint32_t)baudrate;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return false;
|
||||
@@ -704,6 +759,186 @@ bool IDeviceSettings::setTerminationFor(Network net, bool enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<bool> IDeviceSettings::isCommanderResistorEnabledFor(Network net) const {
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
switch(net.getType()) {
|
||||
case Network::Type::LIN: {
|
||||
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return (cfg->CommanderResistor != RESISTOR_OFF);
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDeviceSettings::setCommanderResistorFor(Network net, bool resistor_on) {
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(readonly) {
|
||||
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(net.getType()) {
|
||||
case Network::Type::LIN: {
|
||||
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
cfg->CommanderResistor = resistor_on ? RESISTOR_ON : RESISTOR_OFF;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<LINMode> IDeviceSettings::getLINModeFor(Network net) const {
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
switch(net.getType()) {
|
||||
case Network::Type::LIN: {
|
||||
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return static_cast<LINMode>(cfg->Mode);
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDeviceSettings::setLINModeFor(Network net, LINMode mode) {
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(readonly) {
|
||||
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(net.getType()) {
|
||||
case Network::Type::LIN: {
|
||||
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
cfg->Mode = static_cast<uint8_t>(mode);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint8_t> IDeviceSettings::getLINCommanderResponseTimeFor(Network net) const {
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
switch(net.getType()) {
|
||||
case Network::Type::LIN: {
|
||||
const LIN_SETTINGS* cfg = getLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return cfg->numBitsDelay;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDeviceSettings::setLINCommanderResponseTimeFor(Network net, uint8_t bits) {
|
||||
if(disabled) {
|
||||
report(APIEvent::Type::SettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(readonly) {
|
||||
report(APIEvent::Type::SettingsReadOnly, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(net.getType()) {
|
||||
case Network::Type::LIN: {
|
||||
LIN_SETTINGS* cfg = getMutableLINSettingsFor(net);
|
||||
if(cfg == nullptr) {
|
||||
report(APIEvent::Type::LINSettingsNotAvailable, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
cfg->numBitsDelay = bits;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> bool IDeviceSettings::applyStructure(const T& newStructure) {
|
||||
if(!settingsLoaded) {
|
||||
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
|
||||
|
||||
@@ -19,17 +19,19 @@ std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio
|
||||
const uint64_t currentSector = pos / SectorSize;
|
||||
const uint8_t memLocation = (uint8_t)memType;
|
||||
|
||||
auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com] {
|
||||
uint64_t numWords = amount / 2;
|
||||
|
||||
auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, &numWords] {
|
||||
return com.sendCommand(Command::NeoReadMemory, {
|
||||
memLocation,
|
||||
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)
|
||||
uint8_t(numWords & 0xFF),
|
||||
uint8_t((numWords >> 8) & 0xFF),
|
||||
uint8_t((numWords >> 16) & 0xFF),
|
||||
uint8_t((numWords >> 24) & 0xFF)
|
||||
});
|
||||
}, NeoMemorySDRead, timeout);
|
||||
|
||||
@@ -60,15 +62,17 @@ std::optional<uint64_t> NeoMemoryDiskDriver::writeLogicalDiskAligned(Communicati
|
||||
const uint64_t currentSector = pos / SectorSize;
|
||||
const uint8_t memLocation = (uint8_t)memType;
|
||||
|
||||
auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, from, amount] {
|
||||
uint64_t numWords = amount / 2;
|
||||
|
||||
auto msg = com.waitForMessageSync([¤tSector, &memLocation, &com, from, amount, &numWords] {
|
||||
std::vector<uint8_t> command = {
|
||||
memLocation,
|
||||
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(numWords & 0xFF),
|
||||
uint8_t((numWords >> 8) & 0xFF),
|
||||
};
|
||||
command.insert(command.end(), from, from + amount);
|
||||
return com.sendCommand(Command::NeoWriteMemory, command);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
#include "icsneo/communication/packet/ethernetpacket.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
// VSA Base Class Functions
|
||||
|
||||
// VSAMessage Class Functions
|
||||
std::shared_ptr<Packet> VSAMessage::getPacket() const
|
||||
{
|
||||
auto packet = std::make_shared<Packet>();
|
||||
packet->network = network;
|
||||
reservePacketData(packet);
|
||||
packet->data.insert(packet->data.end(), payload.begin(), payload.end());
|
||||
return packet;
|
||||
}
|
||||
|
||||
// VSAExtendedMessage Class Functions
|
||||
|
||||
void VSAExtendedMessage::appendPacket(std::shared_ptr<Packet> packet) const
|
||||
{
|
||||
packet->data.insert(packet->data.end(), payload.begin(), payload.end());
|
||||
// Set the network if not already set (Happens in AA0F records)
|
||||
if(packet->network.getNetID() == Network::NetID::Invalid) {
|
||||
packet->network = network;
|
||||
}
|
||||
}
|
||||
|
||||
void VSAExtendedMessage::truncatePacket(std::shared_ptr<Packet> packet)
|
||||
{
|
||||
static constexpr auto EthernetLengthOffset = 26u;
|
||||
switch(packet->network.getType()) {
|
||||
case Network::Type::Ethernet:
|
||||
{
|
||||
const auto& packetLength = *reinterpret_cast<uint16_t*>(packet->data.data() + EthernetLengthOffset);
|
||||
const size_t ethernetFrameSize = packetLength - (sizeof(uint16_t) * 2);
|
||||
const size_t bytestreamExpectedSize = sizeof(HardwareEthernetPacket) + ethernetFrameSize;
|
||||
packet->data.resize(bytestreamExpectedSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "icsneo/disk/vsa/vsa02.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA02::VSA02(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA02);
|
||||
constantIndex = *reinterpret_cast<uint16_t*>(recordBytes + 2);
|
||||
flags = *reinterpret_cast<Flags*>(recordBytes + 4);
|
||||
pieceCount = recordBytes[5];
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
samples.insert(samples.end(), recordBytes + 14, recordBytes + 30);
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA02::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "icsneo/disk/vsa/vsa03.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA03::VSA03(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA03);
|
||||
eventType = static_cast<EventType>(*reinterpret_cast<uint16_t*>(recordBytes + 2));
|
||||
eventData = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA03::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "icsneo/disk/vsa/vsa04.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA04::VSA04(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA04);
|
||||
flags = *reinterpret_cast<Flags*>(recordBytes + 2);
|
||||
partitionIndex = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA04::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "icsneo/disk/vsa/vsa05.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA05::VSA05(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA05);
|
||||
errorType = static_cast<ErrorType>(*reinterpret_cast<uint16_t*>(recordBytes + 2));
|
||||
errorNetwork = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 6) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 14);
|
||||
}
|
||||
|
||||
void VSA05::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 7; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "icsneo/disk/vsa/vsa06.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA06::VSA06(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA06);
|
||||
savedSectors.insert(savedSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 2), reinterpret_cast<uint32_t*>(recordBytes + 18));
|
||||
error = *reinterpret_cast<uint16_t*>(recordBytes + 18);
|
||||
savedSectorsHigh = *reinterpret_cast<uint16_t*>(recordBytes + 20);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA06::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "icsneo/disk/vsa/vsa07.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA07::VSA07(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA07);
|
||||
lastSector = *reinterpret_cast<uint32_t*>(recordBytes + 2);
|
||||
currentSector = *reinterpret_cast<uint32_t*>(recordBytes + 6);
|
||||
reserved.insert(reserved.end(), recordBytes + 10, recordBytes + 22);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA07::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "icsneo/disk/vsa/vsa08.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA08::VSA08(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA08);
|
||||
troubleSramCount.insert(troubleSramCount.end(), recordBytes + 2, recordBytes + 6);
|
||||
troubleSectors.insert(troubleSectors.end(), reinterpret_cast<uint32_t*>(recordBytes + 6), reinterpret_cast<uint32_t*>(recordBytes + 20));
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA08::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "icsneo/disk/vsa/vsa09.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA09::VSA09(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA09);
|
||||
serialNumber = *reinterpret_cast<uint32_t*>(recordBytes + 2);
|
||||
firmwareMajorVersion = recordBytes[6];
|
||||
firmwareMinorVersion = recordBytes[7];
|
||||
manufactureMajorRevision = recordBytes[8];
|
||||
manufactureMinorRevision = recordBytes[9];
|
||||
bootloaderMajorVersion = recordBytes[10];
|
||||
bootloaderMinorVersion = recordBytes[11];
|
||||
reserved0.insert(reserved0.end(), recordBytes + 12, recordBytes + 18);
|
||||
hardwareID = static_cast<HardwareID>(recordBytes[18]);
|
||||
reserved1.insert(reserved1.end(), recordBytes + 19, recordBytes + 22);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 22) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA09::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "icsneo/disk/vsa/vsa0b.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto PayloadOffset = 4;
|
||||
|
||||
VSA0B::VSA0B(uint8_t* const recordBytes)
|
||||
: VSAMessage(recordBytes + PayloadOffset, CoreMiniPayloadSize, static_cast<Network::CoreMini>(recordBytes[29]))
|
||||
{
|
||||
setType(VSA::Type::AA0B);
|
||||
captureBitfield = reinterpret_cast<uint16_t*>(recordBytes)[1];
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
reserved = recordBytes[28];
|
||||
checksum = reinterpret_cast<uint16_t*>(recordBytes)[15];
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA0B::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
bool VSA0B::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if((filter->captureBitfield != captureBitfield && filter->captureBitfield != UINT16_MAX) ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "icsneo/disk/vsa/vsa0c.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
VSA0C::VSA0C(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA0C);
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 2);
|
||||
audioPreamble = recordBytes[4];
|
||||
audioHeader = recordBytes[5];
|
||||
pcmData.insert(pcmData.end(), recordBytes + 6, recordBytes + 20);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
vNetBitfield = *reinterpret_cast<VSA0C::VNet*>(recordBytes + 28);
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA0C::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "icsneo/disk/vsa/vsa0d.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto FirstPayloadOffset = 8;
|
||||
static constexpr auto FirstPayloadSize = 12;
|
||||
static constexpr auto ConsecutivePayloadOffset = 4;
|
||||
static constexpr auto LastPayloadSize = 24;
|
||||
static constexpr auto OtherPayloadSize = 28;
|
||||
|
||||
// Parent class functions
|
||||
|
||||
VSA0D::VSA0D(uint8_t* const recordBytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId)
|
||||
: VSAExtendedMessage(messageBytes, numBytes, networkId)
|
||||
{
|
||||
static constexpr auto DWordSize = 4;
|
||||
setType(VSA::Type::AA0D);
|
||||
setIndex(*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0x01FFu);
|
||||
setSequenceNum((*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0xFE00u) >> 9);
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data());
|
||||
for(size_t i = 0; i < payload.size() / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
}
|
||||
|
||||
// First Record Functions
|
||||
|
||||
VSA0DFirst::VSA0DFirst(uint8_t* const recordBytes, uint32_t& runningChecksum)
|
||||
: VSA0D(recordBytes, recordBytes + FirstPayloadOffset, FirstPayloadSize, runningChecksum, static_cast<Network::CoreMini>(recordBytes[29]))
|
||||
{
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
setRecordCount(*reinterpret_cast<uint16_t*>(recordBytes + 6));
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
vNetInfo = *reinterpret_cast<VNet*>(recordBytes + 28);
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
uint32_t* const timestampDWords = reinterpret_cast<uint32_t*>(timestamp);
|
||||
runningChecksum += timestampDWords[0];
|
||||
runningChecksum += timestampDWords[1];
|
||||
}
|
||||
|
||||
void VSA0DFirst::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
void VSA0DFirst::reservePacketData(std::shared_ptr<Packet>& packet) const
|
||||
{
|
||||
uint32_t numMessageBytes = (getRecordCount() - 2) * OtherPayloadSize + FirstPayloadSize + LastPayloadSize;
|
||||
packet->data.reserve(numMessageBytes);
|
||||
}
|
||||
|
||||
void VSA0DFirst::reorderPayload(std::vector<uint8_t>& secondPayload)
|
||||
{
|
||||
std::vector<uint8_t> tempPayload;
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin(), secondPayload.begin() + 4);
|
||||
uint8_t* timestampBytes = reinterpret_cast<uint8_t*>(×tamp);
|
||||
if(timestampIsExtended) {
|
||||
timestampBytes[7] += 0x80;
|
||||
}
|
||||
tempPayload.insert(tempPayload.end(), timestampBytes, timestampBytes + 8);
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin() + 4, secondPayload.end());
|
||||
payload.clear();
|
||||
secondPayload.clear();
|
||||
payload.insert(payload.end(), tempPayload.begin(), tempPayload.begin() + 12); // This is done because the capacity of payload is already 12
|
||||
secondPayload.insert(secondPayload.end(), tempPayload.begin() + 12, tempPayload.end());
|
||||
}
|
||||
|
||||
bool VSA0DFirst::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if((filter->captureBitfield != captureBitfield && filter->captureBitfield != UINT16_MAX) ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Consecutive Record Functions
|
||||
|
||||
VSA0DConsecutive::VSA0DConsecutive(uint8_t* const recordBytes, uint32_t& runningChecksum, std::shared_ptr<VSA0DFirst> first, bool isLastRecord)
|
||||
: VSA0D(recordBytes, recordBytes + ConsecutivePayloadOffset, isLastRecord ? LastPayloadSize : OtherPayloadSize, runningChecksum)
|
||||
{
|
||||
this->first = first;
|
||||
calculatedChecksum = runningChecksum;
|
||||
if(getIndex() == 1) {
|
||||
first->reorderPayload(payload);
|
||||
} else if(isLastRecord) {
|
||||
recordChecksum = *reinterpret_cast<uint32_t*>(recordBytes + 28);
|
||||
doChecksum(recordBytes);
|
||||
} else {
|
||||
setChecksumFailed(first->getChecksumFailed());
|
||||
}
|
||||
setRecordCount(first->getRecordCount());
|
||||
}
|
||||
|
||||
void VSA0DConsecutive::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
setChecksumFailed(recordBytes && calculatedChecksum != recordChecksum);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "icsneo/disk/vsa/vsa0e.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto FirstPayloadOffset = 10;
|
||||
static constexpr auto FirstPayloadSize = 10;
|
||||
static constexpr auto ConsecutivePayloadOffset = 4;
|
||||
static constexpr auto LastPayloadSize = 24;
|
||||
static constexpr auto OtherPayloadSize = 28;
|
||||
|
||||
// Parent class functions
|
||||
|
||||
VSA0E::VSA0E(uint8_t* const recordBytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId)
|
||||
: VSAExtendedMessage(messageBytes, numBytes, networkId)
|
||||
{
|
||||
static constexpr auto DWordSize = 4;
|
||||
setType(VSA::Type::AA0E);
|
||||
setIndex(static_cast<uint16_t>(recordBytes[2]));
|
||||
setSequenceNum(static_cast<uint16_t>(recordBytes[3]));
|
||||
if(getIndex() == 0) {
|
||||
runningChecksum = (static_cast<uint32_t>(payload[0]) << 16) | (static_cast<uint32_t>(payload[1]) << 24);
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data() + 2);
|
||||
for(size_t i = 0; i < (payload.size() - 2) / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
} else {
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data());
|
||||
for(size_t i = 0; i < payload.size() / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First Record Functions
|
||||
|
||||
VSA0EFirst::VSA0EFirst(uint8_t* const recordBytes, uint32_t& runningChecksum)
|
||||
: VSA0E(recordBytes, recordBytes + FirstPayloadOffset, FirstPayloadSize, runningChecksum,
|
||||
static_cast<Network::CoreMini>(*reinterpret_cast<uint16_t*>(recordBytes + 28)))
|
||||
{
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
setRecordCount(*reinterpret_cast<uint32_t*>(recordBytes + 6));
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 20) & UINT63_MAX;
|
||||
timestampIsExtended = (bool)(*reinterpret_cast<uint64_t*>(recordBytes + 20) & (0x8000000000000000));
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 30);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA0EFirst::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for(size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
void VSA0EFirst::reservePacketData(std::shared_ptr<Packet>& packet) const
|
||||
{
|
||||
uint32_t numMessageBytes = (getRecordCount() - 2) * OtherPayloadSize + FirstPayloadSize + LastPayloadSize;
|
||||
packet->data.reserve(numMessageBytes);
|
||||
}
|
||||
|
||||
bool VSA0EFirst::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if((filter->captureBitfield != captureBitfield && filter->captureBitfield != UINT16_MAX) ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VSA0EFirst::reorderPayload(std::vector<uint8_t>& secondPayload)
|
||||
{
|
||||
std::vector<uint8_t> tempPayload;
|
||||
tempPayload.insert(tempPayload.end(), payload.begin(), payload.end());
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin(), secondPayload.begin() + 6);
|
||||
uint8_t* timestampBytes = reinterpret_cast<uint8_t*>(×tamp);
|
||||
if(timestampIsExtended) {
|
||||
timestampBytes[7] += 0x80;
|
||||
}
|
||||
tempPayload.insert(tempPayload.end(), timestampBytes, timestampBytes + 8);
|
||||
tempPayload.insert(tempPayload.end(), secondPayload.begin() + 6, secondPayload.end());
|
||||
payload.clear();
|
||||
secondPayload.clear();
|
||||
payload.insert(payload.end(), tempPayload.begin(), tempPayload.begin() + 10); // This is done because the capacity of payload is already 10
|
||||
secondPayload.insert(secondPayload.end(), tempPayload.begin() + 10, tempPayload.end());
|
||||
}
|
||||
|
||||
// Consecutive Record Functions
|
||||
|
||||
VSA0EConsecutive::VSA0EConsecutive(uint8_t* const recordBytes, uint32_t& runningChecksum, std::shared_ptr<VSA0EFirst> first, bool isLastRecord)
|
||||
: VSA0E(recordBytes, recordBytes + ConsecutivePayloadOffset, isLastRecord ? LastPayloadSize : OtherPayloadSize, runningChecksum)
|
||||
{
|
||||
this->first = first;
|
||||
calculatedChecksum = runningChecksum;
|
||||
if(getIndex() == 1) {
|
||||
first->reorderPayload(payload);
|
||||
} else if(isLastRecord) {
|
||||
recordChecksum = *reinterpret_cast<uint32_t*>(recordBytes + 28);
|
||||
doChecksum(recordBytes);
|
||||
} else {
|
||||
setChecksumFailed(first->getChecksumFailed());
|
||||
}
|
||||
setRecordCount(first->getRecordCount());
|
||||
}
|
||||
|
||||
void VSA0EConsecutive::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
setChecksumFailed(recordBytes && calculatedChecksum != recordChecksum);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "icsneo/disk/vsa/vsa0f.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto FirstPayloadOffset = 18;
|
||||
static constexpr auto FirstPayloadSize = 14;
|
||||
static constexpr auto LastPayloadSize = 24;
|
||||
static constexpr auto OtherPayloadSize = 28;
|
||||
|
||||
// Parent class functions
|
||||
|
||||
VSA0F::VSA0F(uint8_t* const recordBytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId)
|
||||
: VSAExtendedMessage(messageBytes, numBytes, networkId)
|
||||
{
|
||||
static constexpr auto DWordSize = 4;
|
||||
setType(VSA::Type::AA0F);
|
||||
setIndex(*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0x01FFu);
|
||||
setSequenceNum((*reinterpret_cast<uint16_t*>(recordBytes + 2) & 0xFE00u) >> 9);
|
||||
if(getIndex() == 0) {
|
||||
runningChecksum = (static_cast<uint32_t>(payload[0]) << 16) | (static_cast<uint32_t>(payload[1]) << 24);
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(payload.data() + 2);
|
||||
for (size_t i = 0; i < (payload.size() - 2) / DWordSize; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
} else {
|
||||
uint32_t* dwords = reinterpret_cast<uint32_t*>(recordBytes);
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
runningChecksum += dwords[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First Record Functions
|
||||
|
||||
VSA0FFirst::VSA0FFirst(uint8_t* const recordBytes, uint32_t& runningChecksum)
|
||||
: VSA0F(recordBytes, recordBytes + FirstPayloadOffset, FirstPayloadSize, runningChecksum)
|
||||
{
|
||||
captureBitfield = *reinterpret_cast<uint16_t*>(recordBytes + 4);
|
||||
uint16_t byteCount = *reinterpret_cast<uint16_t*>(recordBytes + 6);
|
||||
uint16_t recordCount;
|
||||
if(byteCount <= FirstPayloadSize) {
|
||||
recordCount = 1;
|
||||
} else if(byteCount <= FirstPayloadSize + LastPayloadSize) {
|
||||
recordCount = 2;
|
||||
} else {
|
||||
byteCount -= FirstPayloadSize + LastPayloadSize;
|
||||
recordCount = 2 + byteCount / OtherPayloadSize;
|
||||
if (byteCount % OtherPayloadSize != 0) {
|
||||
recordCount += 1;
|
||||
}
|
||||
}
|
||||
setRecordCount(recordCount);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 8) & UINT63_MAX;
|
||||
checksum = *reinterpret_cast<uint16_t*>(recordBytes + 16);
|
||||
doChecksum(recordBytes);
|
||||
// Network ID is not found in first record for AA0F
|
||||
// Only the subsequent records have the Network ID in the payload
|
||||
}
|
||||
|
||||
void VSA0FFirst::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint16_t* words = reinterpret_cast<uint16_t*>(recordBytes);
|
||||
uint16_t sum = 0;
|
||||
for (size_t i = 0; i < 15; i++) {
|
||||
sum += words[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum);
|
||||
}
|
||||
|
||||
void VSA0FFirst::reservePacketData(std::shared_ptr<Packet>& packet) const
|
||||
{
|
||||
uint32_t numMessageBytes = (getRecordCount() - 2) * OtherPayloadSize + FirstPayloadSize + LastPayloadSize;
|
||||
packet->data.reserve(numMessageBytes);
|
||||
}
|
||||
|
||||
bool VSA0FFirst::filter(const std::shared_ptr<VSAMessageReadFilter> filter)
|
||||
{
|
||||
if(filter->captureBitfield != captureBitfield ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.first) > timestamp ||
|
||||
getICSTimestampFromTimepoint(filter->readRange.second) < timestamp) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Consecutive Record Functions
|
||||
|
||||
VSA0FConsecutive::VSA0FConsecutive(uint8_t* const recordBytes, uint32_t& runningChecksum, std::shared_ptr<VSA0FFirst> first, bool isLastRecord)
|
||||
: VSA0F(recordBytes, recordBytes + 4, isLastRecord ? LastPayloadSize : OtherPayloadSize, runningChecksum)
|
||||
{
|
||||
this->first = first;
|
||||
calculatedChecksum = runningChecksum;
|
||||
if(isLastRecord) {
|
||||
doChecksum(recordBytes);
|
||||
} else {
|
||||
network = Network(static_cast<Network::CoreMini>(*reinterpret_cast<uint16_t*>(recordBytes + 28))); // Network ID is stored in 25th and 26th recordBytes of payload
|
||||
}
|
||||
setRecordCount(first->getRecordCount());
|
||||
}
|
||||
|
||||
void VSA0FConsecutive::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
setChecksumFailed(recordBytes && calculatedChecksum != 0);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "icsneo/disk/vsa/vsa6a.h"
|
||||
#include "icsneo/disk/diskdriver.h"
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
static constexpr auto PayloadOffset = 56;
|
||||
static constexpr auto PayloadSize = 452;
|
||||
static constexpr auto TimestampOffset = 48;
|
||||
static constexpr auto TimestampSize = 8;
|
||||
|
||||
VSA6A::VSA6A(uint8_t* const recordBytes)
|
||||
: VSA()
|
||||
{
|
||||
setType(VSA::Type::AA6A);
|
||||
|
||||
sequenceNum = *reinterpret_cast<uint32_t*>(recordBytes + 34);
|
||||
totalSectors = *reinterpret_cast<uint32_t*>(recordBytes + 38);
|
||||
reserved = *reinterpret_cast<uint32_t*>(recordBytes + 42);
|
||||
timestamp = *reinterpret_cast<uint64_t*>(recordBytes + 46) & UINT63_MAX;
|
||||
timestampSum = *reinterpret_cast<uint16_t*>(recordBytes + 54);
|
||||
data.insert(data.end(), recordBytes + 56, recordBytes + 508);
|
||||
checksum = *reinterpret_cast<uint32_t*>(recordBytes + 508);
|
||||
doChecksum(recordBytes);
|
||||
}
|
||||
|
||||
void VSA6A::doChecksum(uint8_t* recordBytes)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
for(size_t i = PayloadOffset; i < PayloadOffset+ PayloadSize; i++) {
|
||||
sum += recordBytes[i];
|
||||
}
|
||||
uint16_t tSum = 0;
|
||||
for(size_t i = TimestampOffset; i < TimestampOffset + TimestampSize; i++) {
|
||||
tSum += recordBytes[i];
|
||||
}
|
||||
setChecksumFailed(sum != checksum || tSum != timestampSum);
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
#include "icsneo/disk/vsa/vsaparser.h"
|
||||
#include "icsneo/disk/vsa/vsa02.h"
|
||||
#include "icsneo/disk/vsa/vsa03.h"
|
||||
#include "icsneo/disk/vsa/vsa04.h"
|
||||
#include "icsneo/disk/vsa/vsa05.h"
|
||||
#include "icsneo/disk/vsa/vsa06.h"
|
||||
#include "icsneo/disk/vsa/vsa07.h"
|
||||
#include "icsneo/disk/vsa/vsa08.h"
|
||||
#include "icsneo/disk/vsa/vsa09.h"
|
||||
#include "icsneo/disk/vsa/vsa0b.h"
|
||||
#include "icsneo/disk/vsa/vsa0c.h"
|
||||
#include "icsneo/disk/vsa/vsa0d.h"
|
||||
#include "icsneo/disk/vsa/vsa0e.h"
|
||||
#include "icsneo/disk/vsa/vsa0f.h"
|
||||
#include "icsneo/disk/vsa/vsa6a.h"
|
||||
#include "icsneo/disk/diskdriver.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace icsneo;
|
||||
|
||||
bool VSAParser::parseBytes(uint8_t* const bytes, uint64_t arrLen)
|
||||
{
|
||||
uint64_t bytesOffset = 0;
|
||||
while(bytesOffset + VSA::StandardRecordSize <= arrLen) { // Enough bytes to read for Standard Record
|
||||
if(bytes[bytesOffset] != 0xAAu) {
|
||||
// Invalid Input
|
||||
return false;
|
||||
}
|
||||
switch(bytes[bytesOffset + 1]) {
|
||||
case 0x00u: // Pad Record
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x01u: // Message Data (Deprecated)
|
||||
hasDeprecatedRecords = true;
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x02u: // Logdata Record
|
||||
if(settings.extractAA02) {
|
||||
vsaRecords.push_back(std::make_shared<VSA02>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x03u: // Event Record
|
||||
if(settings.extractAA03) {
|
||||
vsaRecords.push_back(std::make_shared<VSA03>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x04u: // Partition Info Record
|
||||
if(settings.extractAA04) {
|
||||
vsaRecords.push_back(std::make_shared<VSA04>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x05u: // Application Error Record
|
||||
if(settings.extractAA05) {
|
||||
vsaRecords.push_back(std::make_shared<VSA05>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x06u: // Debug/Internal
|
||||
if(settings.extractAA06) {
|
||||
vsaRecords.push_back(std::make_shared<VSA06>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x07u: // Debug/Internal
|
||||
if(settings.extractAA07) {
|
||||
vsaRecords.push_back(std::make_shared<VSA07>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x08u: // Buffer Info Record
|
||||
if(settings.extractAA08) {
|
||||
vsaRecords.push_back(std::make_shared<VSA08>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x09u: // Device Info Record
|
||||
if(settings.extractAA09) {
|
||||
vsaRecords.push_back(std::make_shared<VSA09>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Au: // Logger Info Configuration (Deprecated)
|
||||
hasDeprecatedRecords = true;
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Bu: // Message Data
|
||||
if(settings.extractAA0B) {
|
||||
auto record = std::make_shared<VSA0B>(bytes + bytesOffset);
|
||||
vsaRecords.push_back(record);
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Cu: // PCM Audio Data
|
||||
if(settings.extractAA0C) {
|
||||
vsaRecords.push_back(std::make_shared<VSA0C>(bytes + bytesOffset));
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Du: // Message Data (Extended)
|
||||
if(settings.extractAA0D) {
|
||||
if(!handleExtendedRecord(bytes, bytesOffset, VSA::Type::AA0D)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Eu: // Message Data (Extended)
|
||||
if(settings.extractAA0E) {
|
||||
if(!handleExtendedRecord(bytes, bytesOffset, VSA::Type::AA0E)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x0Fu: // Message Data (Extended)
|
||||
if(settings.extractAA0F) {
|
||||
if(!handleExtendedRecord(bytes, bytesOffset, VSA::Type::AA0F)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bytesOffset += VSA::StandardRecordSize;
|
||||
break;
|
||||
case 0x6Au: // Logger Configuration Backup
|
||||
if(bytesOffset + Disk::SectorSize <= arrLen) {
|
||||
if(settings.extractAA6A) {
|
||||
vsaRecords.push_back(std::make_shared<VSA6A>(bytes + bytesOffset));
|
||||
}
|
||||
}
|
||||
bytesOffset += Disk::SectorSize;
|
||||
break;
|
||||
default:
|
||||
// Unhandled VSA Record Type
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VSAParser::handleExtendedRecord(uint8_t* const bytes, uint64_t& bytesOffset, VSA::Type type)
|
||||
{
|
||||
// Gather info about the extended record sequence of the record contained in bytes
|
||||
std::shared_ptr<VSAExtendedMessage> first;
|
||||
uint16_t seqNum;
|
||||
ExtendedMessageState::ExtendedRecordSeqInfo* seqInfo;
|
||||
uint32_t runningChecksum = 0;
|
||||
switch(type) {
|
||||
case VSA::Type::AA0D:
|
||||
first = std::make_shared<VSA0DFirst>(bytes + bytesOffset, runningChecksum);
|
||||
seqNum = first->getSequenceNum();
|
||||
seqInfo = &state.vsa0DSeqInfo[seqNum];
|
||||
break;
|
||||
case VSA::Type::AA0E:
|
||||
first = std::make_shared<VSA0EFirst>(bytes + bytesOffset, runningChecksum);
|
||||
seqNum = first->getSequenceNum();
|
||||
seqInfo = &state.vsa0ESeqInfo[seqNum];
|
||||
break;
|
||||
case VSA::Type::AA0F:
|
||||
first = std::make_shared<VSA0FFirst>(bytes + bytesOffset, runningChecksum);
|
||||
seqNum = first->getSequenceNum();
|
||||
seqInfo = &state.vsa0FSeqInfo[seqNum];
|
||||
break;
|
||||
default:
|
||||
return false; // Invalid type was passed
|
||||
}
|
||||
|
||||
if(seqInfo->nextIndex == 0 && seqInfo->records.size() == 0) { // This is the first record in the sequence
|
||||
if(first->getIndex() != 0) {
|
||||
seqInfo->clear();
|
||||
report(APIEvent::Type::VSAExtendedMessageError, APIEvent::Severity::EventWarning);
|
||||
return true; // This is not actually the first record
|
||||
}
|
||||
seqInfo->records.push_back(first);
|
||||
seqInfo->totalRecordCount = first->getRecordCount();
|
||||
seqInfo->nextIndex++;
|
||||
seqInfo->runningChecksum = runningChecksum;
|
||||
} else if(seqInfo->nextIndex < seqInfo->totalRecordCount && seqInfo->records.size() > 0) { // Consecutive Record
|
||||
std::shared_ptr<VSAExtendedMessage> consecutive;
|
||||
bool isLast = seqInfo->nextIndex == seqInfo->totalRecordCount - 1;
|
||||
|
||||
// Construct the consecutive record from bytes
|
||||
switch(type) {
|
||||
case VSA::Type::AA0D:
|
||||
consecutive = std::make_shared<VSA0DConsecutive>(
|
||||
bytes + bytesOffset,
|
||||
seqInfo->runningChecksum,
|
||||
std::dynamic_pointer_cast<VSA0DFirst>(seqInfo->records[0]),
|
||||
isLast
|
||||
);
|
||||
break;
|
||||
case VSA::Type::AA0E:
|
||||
consecutive = std::make_shared<VSA0EConsecutive>(
|
||||
bytes + bytesOffset,
|
||||
seqInfo->runningChecksum,
|
||||
std::dynamic_pointer_cast<VSA0EFirst>(seqInfo->records[0]),
|
||||
isLast
|
||||
);
|
||||
break;
|
||||
case VSA::Type::AA0F:
|
||||
consecutive = std::make_shared<VSA0FConsecutive>(
|
||||
bytes + bytesOffset,
|
||||
seqInfo->runningChecksum,
|
||||
std::dynamic_pointer_cast<VSA0FFirst>(seqInfo->records[0]),
|
||||
isLast
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if(consecutive->getIndex() == seqInfo->nextIndex && consecutive->getSequenceNum() == seqNum) { // This record is valid in the sequence
|
||||
seqInfo->records.push_back(consecutive);
|
||||
seqInfo->nextIndex++;
|
||||
} else { // Sequence is out of order/invalid
|
||||
// Throw away incomplete sequence and report warning
|
||||
seqInfo->clear();
|
||||
report(APIEvent::Type::VSAExtendedMessageError, APIEvent::Severity::EventWarning);
|
||||
// Save data for new sequence
|
||||
if(first->getIndex() == 0) {
|
||||
seqInfo->records.push_back(first);
|
||||
seqInfo->totalRecordCount = first->getRecordCount();
|
||||
seqInfo->nextIndex++;
|
||||
seqInfo->runningChecksum = runningChecksum;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(seqInfo->nextIndex == seqInfo->totalRecordCount) { // This is the last record in the sequence
|
||||
if(consecutive->getChecksumFailed()) {
|
||||
// Fail out if checksum fails
|
||||
seqInfo->clear();
|
||||
return false;
|
||||
}
|
||||
vsaRecords.insert(vsaRecords.end(), seqInfo->records.begin(), seqInfo->records.end());
|
||||
seqInfo->clear();
|
||||
}
|
||||
} else {
|
||||
return false; // Undefined behavior
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VSAParser::RecordParseStatus VSAParser::getRecordFromBytes(uint8_t* const bytes, size_t arrLen, std::shared_ptr<VSA>& record)
|
||||
{
|
||||
record = nullptr;
|
||||
if(arrLen < VSA::StandardRecordSize) {
|
||||
// Not enough bytes
|
||||
return VSAParser::RecordParseStatus::InsufficientData;
|
||||
} else if(bytes[0] != 0xAAu) {
|
||||
return VSAParser::RecordParseStatus::NotARecordStart;
|
||||
} else {
|
||||
switch(bytes[1]) {
|
||||
case 0x00u: // Pad Record
|
||||
return VSAParser::RecordParseStatus::Pad;
|
||||
case 0x01u: // Message Data (Deprecated)
|
||||
return VSAParser::RecordParseStatus::Deprecated;
|
||||
case 0x02u: // Logdata Record
|
||||
if(settings.extractAA02) {
|
||||
record = std::make_shared<VSA02>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x03u: // Event Record
|
||||
if(settings.extractAA03) {
|
||||
record = std::make_shared<VSA03>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x04u: // Partition Info Record
|
||||
if(settings.extractAA04) {
|
||||
record = std::make_shared<VSA04>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x05u: // Application Error Record
|
||||
if(settings.extractAA05) {
|
||||
record = std::make_shared<VSA05>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x06u: // Debug/Internal
|
||||
if(settings.extractAA06) {
|
||||
record = std::make_shared<VSA06>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x07u: // Debug/Internal
|
||||
if(settings.extractAA07) {
|
||||
record = std::make_shared<VSA07>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x08u: // Buffer Info Record
|
||||
if(settings.extractAA08) {
|
||||
record = std::make_shared<VSA08>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x09u: // Device Info Record
|
||||
if(settings.extractAA09) {
|
||||
record = std::make_shared<VSA09>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x0Au:
|
||||
return VSAParser::RecordParseStatus::Deprecated;
|
||||
case 0x0Bu: // Message Data
|
||||
if(settings.extractAA0B) {
|
||||
record = std::make_shared<VSA0B>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x0Cu: // PCM Audio Data
|
||||
if(settings.extractAA0C) {
|
||||
record = std::make_shared<VSA0C>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
case 0x0Du: // Message Data (Extended)
|
||||
if(settings.extractAA0D) {
|
||||
uint32_t payloadChecksum = 0;
|
||||
const auto& vsa = std::make_shared<VSA0DFirst>(bytes, payloadChecksum);
|
||||
record = vsa;
|
||||
if(vsa->getIndex() == 0) {
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
// This returns the consecutive record as a first record
|
||||
return VSAParser::RecordParseStatus::ConsecutiveExtended;
|
||||
}
|
||||
break;
|
||||
case 0x0Eu: // Message Data (Extended)
|
||||
if(settings.extractAA0E) {
|
||||
uint32_t payloadChecksum = 0;
|
||||
const auto& vsa = std::make_shared<VSA0EFirst>(bytes, payloadChecksum);
|
||||
record = vsa;
|
||||
if(vsa->getIndex() == 0) {
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
// This returns the consecutive record as a first record
|
||||
return VSAParser::RecordParseStatus::ConsecutiveExtended;
|
||||
}
|
||||
break;
|
||||
case 0x0Fu: // Message Data (Extended)
|
||||
if(settings.extractAA0F) {
|
||||
uint32_t payloadChecksum = 0;
|
||||
const auto& vsa = std::make_shared<VSA0FFirst>(bytes, payloadChecksum);
|
||||
record = vsa;
|
||||
if(vsa->getIndex() == 0) {
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
// This returns the consecutive record as a first record
|
||||
return VSAParser::RecordParseStatus::ConsecutiveExtended;
|
||||
}
|
||||
break;
|
||||
case 0x6Au: // Logger Configuration Backup
|
||||
if(settings.extractAA6A) {
|
||||
if(arrLen < Disk::SectorSize) {
|
||||
return VSAParser::RecordParseStatus::InsufficientData;
|
||||
}
|
||||
record = std::make_shared<VSA6A>(bytes);
|
||||
return VSAParser::RecordParseStatus::Success;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unhandled VSA Record Type
|
||||
return VSAParser::RecordParseStatus::UnknownRecordType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return VSAParser::RecordParseStatus::FilteredOut;
|
||||
}
|
||||
|
||||
void VSAParser::clearParseState()
|
||||
{
|
||||
for(size_t i = 0; i < state.vsa0DSeqInfo.size(); i++) {
|
||||
state.vsa0DSeqInfo[i].clear();
|
||||
}
|
||||
for(size_t i = 0; i < state.vsa0ESeqInfo.size(); i++) {
|
||||
state.vsa0ESeqInfo[i].clear();
|
||||
}
|
||||
for(size_t i = 0; i < state.vsa0DSeqInfo.size(); i++) {
|
||||
state.vsa0ESeqInfo[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool VSAParser::extractMessagePackets(std::vector<std::shared_ptr<Packet>>& packets)
|
||||
{
|
||||
if(settings != Settings::messageRecords()) {
|
||||
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
|
||||
return false; // We do not have exclusively message records
|
||||
}
|
||||
std::shared_ptr<Packet> packet;
|
||||
bool activeExtendedMessage = false;
|
||||
VSA::Type previousRecordType = VSA::Type::Invalid;
|
||||
for(const auto& record : vsaRecords) {
|
||||
VSA::Type activeRecordType = record->getType();
|
||||
switch(activeRecordType) {
|
||||
// Handle standard message records
|
||||
case VSA::Type::AA0B: {
|
||||
if(activeExtendedMessage) {
|
||||
// Non-terminated extended message record
|
||||
// There was a failure/unexpected behavior in the parsing process
|
||||
report(APIEvent::Type::VSAExtendedMessageError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<VSAMessage> messageRecord = std::dynamic_pointer_cast<VSAMessage>(record);
|
||||
if(!settings.messageFilter || messageRecord->filter(settings.messageFilter)) {
|
||||
packet = messageRecord->getPacket();
|
||||
packets.push_back(packet);
|
||||
}
|
||||
packet = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle extended message records
|
||||
case VSA::Type::AA0D:
|
||||
case VSA::Type::AA0E:
|
||||
case VSA::Type::AA0F: {
|
||||
std::shared_ptr<VSAExtendedMessage> extendedMessageRecord = std::dynamic_pointer_cast<VSAExtendedMessage>(record);
|
||||
|
||||
if(!activeExtendedMessage) { // Start new extended message packet
|
||||
packet = extendedMessageRecord->getPacket();
|
||||
activeExtendedMessage = true;
|
||||
previousRecordType = extendedMessageRecord->getType();
|
||||
} else if(previousRecordType == activeRecordType) { // Continue existing extended message packet
|
||||
extendedMessageRecord->appendPacket(packet);
|
||||
if(extendedMessageRecord->getRecordCount() == static_cast<uint32_t>(extendedMessageRecord->getIndex() + 1)) { // Last record in sequence
|
||||
if(!settings.messageFilter || extendedMessageRecord->filter(settings.messageFilter)) {
|
||||
VSAExtendedMessage::truncatePacket(packet);
|
||||
packets.push_back(packet);
|
||||
}
|
||||
activeExtendedMessage = false;
|
||||
packet = nullptr;
|
||||
previousRecordType = activeRecordType;
|
||||
}
|
||||
} else {
|
||||
// Non-terminated extended message record
|
||||
// There was a failure/unexpected behavior in the parsing process
|
||||
activeExtendedMessage = false;
|
||||
packet = nullptr;
|
||||
previousRecordType = VSA::Type::Invalid;
|
||||
report(APIEvent::Type::VSAOtherError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Non-message record discovered
|
||||
report(APIEvent::Type::VSAOtherError, APIEvent::Severity::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
vsaRecords.clear();
|
||||
return true;
|
||||
}
|
||||
+1
-1
@@ -64,7 +64,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'libicsneo'
|
||||
copyright = '2018-2023, Intrepid Control Systems, Inc.'
|
||||
copyright = '2018-2024, Intrepid Control Systems, Inc.'
|
||||
author = 'Intrepid Control Systems, Inc.'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
||||
@@ -64,7 +64,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'libicsneo'
|
||||
copyright = '2018-2023, Intrepid Control Systems, Inc.'
|
||||
copyright = '2018-2024, Intrepid Control Systems, Inc.'
|
||||
author = 'Intrepid Control Systems, Inc.'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
||||
@@ -8,6 +8,7 @@ option(LIBICSNEO_BUILD_CPP_LIN_EXAMPLE "Build the LIN example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_LIVEDATA_EXAMPLE "Build the Live Data example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_COREMINI_EXAMPLE "Build the Coremini example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE "Build the MDIO example." ON)
|
||||
option(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE "Build the VSA example." ON)
|
||||
|
||||
# Disabled until we properly build these in-tree
|
||||
# option(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE "Build the command-line interactive C# example." OFF)
|
||||
@@ -53,6 +54,10 @@ if(LIBICSNEO_BUILD_CPP_MDIO_EXAMPLE)
|
||||
add_subdirectory(cpp/mdio)
|
||||
endif()
|
||||
|
||||
if(LIBICSNEO_BUILD_CPP_VSA_EXAMPLE)
|
||||
add_subdirectory(cpp/vsa)
|
||||
endif()
|
||||
|
||||
# if(LIBICSNEO_BUILD_CSHARP_INTERACTIVE_EXAMPLE)
|
||||
# add_subdirectory(csharp)
|
||||
# endif()
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneoc-interactive-example VERSION 0.2.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Include libicsneo's include directory
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
|
||||
|
||||
if(UNIX)
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS)
|
||||
endif()
|
||||
|
||||
add_executable(libicsneoc-interactive-example src/main.c)
|
||||
if(UNIX)
|
||||
target_link_libraries(libicsneoc-interactive-example ${CMAKE_DL_LIBS})
|
||||
|
||||
@@ -166,7 +166,9 @@ char getCharInput(int numArgs, ...) {
|
||||
va_end(vaList);
|
||||
|
||||
while(!found) {
|
||||
fgets(input, 99, stdin);
|
||||
if(fgets(input, 99, stdin) == NULL) {
|
||||
break;
|
||||
}
|
||||
if(strlen(input) == 2) {
|
||||
for(int i = 0; i < numArgs; ++i) {
|
||||
if(input[0] == *(list + i)) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneoc-legacy-lin-example VERSION 0.2.0)
|
||||
|
||||
add_executable(libicsneoc-legacy-lin-example lin/main.c)
|
||||
add_executable(libicsneoc-legacy-device-settings-example deviceSettings/main.c)
|
||||
target_link_libraries(libicsneoc-legacy-lin-example icsneolegacy)
|
||||
|
||||
@@ -37,18 +37,17 @@ int main() {
|
||||
printf("ICS icsneolegacy.dll version %u\n\n", ver);
|
||||
// Find and attempt to open device
|
||||
//legacy open device
|
||||
int numDevices = 10;
|
||||
NeoDevice devices[10];
|
||||
void* hObject; // holds a handle to the neoVI object
|
||||
int numDevices = 255;
|
||||
NeoDeviceEx devices[255] = {0};
|
||||
void* hObject = NULL; // holds a handle to the neoVI object
|
||||
int iRetVal = 0;
|
||||
int deviceTypes = 0;
|
||||
int iResult = 0;
|
||||
SDeviceSettings pSettings;
|
||||
SDeviceSettings pSettings = {0};
|
||||
|
||||
iRetVal = icsneoFindNeoDevices(deviceTypes, devices, &numDevices);
|
||||
if(iRetVal) {
|
||||
iRetVal = icsneoFindDevices(devices, &numDevices, NULL, 0, NULL, 0);
|
||||
if(iRetVal && numDevices > 0) {
|
||||
// Attempt to open the selected device, enable message polling, and go online
|
||||
iRetVal = icsneoOpenNeoDevice(&devices[0], &hObject, NULL, 1, 0);
|
||||
iRetVal = icsneoOpenDevice(&devices[0], &hObject, NULL, 1, 0, NULL, 0);
|
||||
if(iRetVal) {
|
||||
puts("Device found and opened!\n");
|
||||
} else {
|
||||
|
||||
@@ -31,17 +31,16 @@ int main() {
|
||||
printf("ICS icsneolegacy.dll version %u\n\n", ver);
|
||||
// Find and attempt to open device
|
||||
//legacy open device
|
||||
int numDevices = 10;
|
||||
NeoDevice devices[10];
|
||||
void* hObject; // holds a handle to the neoVI object
|
||||
int numDevices = 255;
|
||||
NeoDeviceEx devices[255] = {0};
|
||||
void* hObject = NULL; // holds a handle to the neoVI object
|
||||
int iRetVal = 0;
|
||||
int deviceTypes = 0;
|
||||
int iResult = 0;
|
||||
|
||||
iRetVal = icsneoFindNeoDevices(deviceTypes, devices, &numDevices);
|
||||
if(iRetVal) {
|
||||
iRetVal = icsneoFindDevices(devices, &numDevices, NULL, 0, NULL, 0);
|
||||
if(iRetVal && numDevices < 0) {
|
||||
// Attempt to open the selected device, enable message polling, and go online
|
||||
iRetVal = icsneoOpenNeoDevice(&devices[0], &hObject, NULL, 1, 0);
|
||||
iRetVal = icsneoOpenDevice(&devices[0], &hObject, NULL, 1, 0, NULL, 0);
|
||||
if(iRetVal) {
|
||||
printf("Device found and opened!\n");
|
||||
} else {
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneoc-simple-lin-example VERSION 0.2.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Include libicsneo's include directory
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
|
||||
|
||||
if(UNIX)
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS)
|
||||
endif()
|
||||
|
||||
add_executable(libicsneoc-simple-lin-example lin/main.c)
|
||||
if(UNIX)
|
||||
target_link_libraries(libicsneoc-simple-lin-example ${CMAKE_DL_LIBS})
|
||||
|
||||
@@ -161,7 +161,9 @@ char getCharInput(int numArgs, ...) {
|
||||
va_end(vaList);
|
||||
|
||||
while(!found) {
|
||||
fgets(input, 99, stdin);
|
||||
if(fgets(input, 99, stdin) == NULL) {
|
||||
break;
|
||||
}
|
||||
if(strlen(input) == 2) {
|
||||
for(int i = 0; i < numArgs; ++i) {
|
||||
if(input[0] == *(list + i)) {
|
||||
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-a2b VERSION 0.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-a2b src/a2b.cpp)
|
||||
target_link_libraries(libicsneocpp-a2b icsneocpp)
|
||||
@@ -233,11 +233,93 @@ void example5(std::shared_ptr<icsneo::Device>& rada2b) {
|
||||
std::thread listenerThread{listener};
|
||||
|
||||
// Transmit wave file using example0
|
||||
|
||||
example0(rada2b);
|
||||
listenerThread.join();
|
||||
}
|
||||
|
||||
// Example 6: Retrieving A2B bus status using I2C messaages.
|
||||
void example6(std::shared_ptr<icsneo::Device>& rada2b) {
|
||||
std::shared_ptr<icsneo::I2CMessage> msg = std::make_shared<icsneo::I2CMessage>();
|
||||
std::shared_ptr<icsneo::MessageFilter> msgFilter = std::make_shared<icsneo::MessageFilter>(icsneo::Network::NetID::I2C2);
|
||||
|
||||
msg->network = icsneo::Network(icsneo::Network::NetID::I2C2);
|
||||
msg->controlBytes.resize(1);
|
||||
msg->controlBytes[0] = static_cast<uint8_t>(0x17u); // Register address for A2B INTTYPE
|
||||
msg->dataBytes.resize(1, 0);
|
||||
msg->direction = icsneo::I2CMessage::Direction::Read;
|
||||
msg->deviceMode = icsneo::I2CMessage::DeviceMode::Controller;
|
||||
msg->address = static_cast<uint16_t>(0x68); // A2B master node address.
|
||||
msg->isTXMsg = true;
|
||||
|
||||
auto handler = rada2b->addMessageCallback(std::make_shared<icsneo::MessageCallback>(
|
||||
[] (std::shared_ptr<icsneo::Message> newMsg) {
|
||||
|
||||
if(newMsg->type == icsneo::Message::Type::Frame) {
|
||||
const auto& frame = std::dynamic_pointer_cast<icsneo::Frame>(newMsg);
|
||||
if(frame && frame->network.getNetID() == icsneo::Network::NetID::I2C2) {
|
||||
const auto& i2cMessage = std::dynamic_pointer_cast<icsneo::I2CMessage>(frame);
|
||||
|
||||
if(!i2cMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(i2cMessage->controlBytes.size() == 1 && i2cMessage->direction == icsneo::I2CMessage::Direction::Read) {
|
||||
if(i2cMessage->controlBytes[0] == 0x17u) {
|
||||
if(i2cMessage->dataBytes.size() == 1) {
|
||||
std::cout << "Current A2B bus status INTTYPE code: " << static_cast<int>(i2cMessage->dataBytes[0]) << '\n';
|
||||
}
|
||||
} else if(i2cMessage->controlBytes[0] == 0x03u) {
|
||||
if(i2cMessage->dataBytes.size() == 1) {
|
||||
std::cout << "A2B_PRODUCT register: " << static_cast<int>(i2cMessage->dataBytes[0]) << std::endl;
|
||||
}
|
||||
} else if(i2cMessage->controlBytes[0] == 0x02u) {
|
||||
if(i2cMessage->dataBytes.size() == 1) {
|
||||
std::cout << "A2B_VENDOR register: " << static_cast<int>(i2cMessage->dataBytes[0]) << std::endl;
|
||||
}
|
||||
} else if(i2cMessage->controlBytes[0] == 0x1C) {
|
||||
if(i2cMessage->dataBytes.size() == 1) {
|
||||
std::cout << "A2B_INTMSK1 register value: " << static_cast<int>(i2cMessage->dataBytes[0]) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
, msgFilter));
|
||||
if(!rada2b->transmit(msg)) {
|
||||
std::cout << "Failed to transmit." << std::endl;
|
||||
}
|
||||
msg->controlBytes[0] = 0x03; // Address for A2B_PRODUCT register
|
||||
|
||||
if(!rada2b->transmit(msg)) {
|
||||
std::cout << "Failed to transmit." << std::endl;
|
||||
}
|
||||
|
||||
msg->controlBytes[0] = 0x02; // Address for A2B_VENDOR register
|
||||
if(!rada2b->transmit(msg)) {
|
||||
std::cout << "Failed to transmit." << std::endl;
|
||||
}
|
||||
|
||||
msg->controlBytes[0] = 0x1C ; // Address for A2B_INTMSK1 register
|
||||
msg->dataBytes[0] = 0x11;
|
||||
msg->direction = icsneo::I2CMessage::Direction::Write;
|
||||
// Write register
|
||||
if(!rada2b->transmit(msg)) {
|
||||
std::cout << "Failed to transmit" << std::endl;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
msg->direction = icsneo::I2CMessage::Direction::Read;
|
||||
|
||||
// Read register
|
||||
if(!rada2b->transmit(msg)) {
|
||||
std::cout << "Failed to transmit." << std::endl;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
|
||||
rada2b->removeMessageCallback(handler);
|
||||
}
|
||||
|
||||
void displayUsage() {
|
||||
std::cout << "libicsneo A2B example" << std::endl;
|
||||
std::cout << "Example must be ran with rada2b as slave on TDM4 32 bit channel size and one ADI master node" << std::endl;
|
||||
@@ -254,6 +336,7 @@ void displayUsage() {
|
||||
std::cout << "3\tA2BMessage API" << std::endl;
|
||||
std::cout << "4\tPackaging and transmitting sine wave using A2BMessage API" << std::endl;
|
||||
std::cout << "5\tWave loopback" << std::endl;
|
||||
std::cout << "6\tRead/write I2C registers on A2B board" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -277,7 +360,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
int option = atoi(arguments[2].c_str());
|
||||
|
||||
if(option < 0 || option > 5) {
|
||||
if(option < 0 || option > 6) {
|
||||
std::cerr << "Invalid usage." << std::endl;
|
||||
displayUsage();
|
||||
return EXIT_FAILURE;
|
||||
@@ -345,6 +428,9 @@ int main(int argc, char** argv) {
|
||||
case 5:
|
||||
example5(rada2b);
|
||||
break;
|
||||
case 6:
|
||||
example6(rada2b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-coremini VERSION 0.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-coremini src/coremini.cpp)
|
||||
target_link_libraries(libicsneocpp-coremini icsneocpp)
|
||||
@@ -1,5 +1,5 @@
|
||||
// Usage:
|
||||
// ./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH]
|
||||
// ./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH] [FLASH | SD]
|
||||
|
||||
|
||||
#include <iostream>
|
||||
@@ -8,14 +8,14 @@
|
||||
|
||||
void displayUsage() {
|
||||
std::cout << "Usage:\n";
|
||||
std::cout << "./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH]\n";
|
||||
std::cout << "./libicsneocpp-coremini [DEVICE_SERIAL] [COREMINI_SCRIPT_PATH] [FLASH | SD]\n";
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::vector<std::string> arguments(argv, argv + argc);
|
||||
|
||||
if(arguments.size() != 3) {
|
||||
if(arguments.size() != 4) {
|
||||
displayUsage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@@ -50,14 +50,25 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!device->uploadCoremini(std::make_unique<std::ifstream>(arguments[2], std::ios::binary), icsneo::Disk::MemoryType::Flash))
|
||||
{
|
||||
std::string memTypeString = arguments[3];
|
||||
|
||||
icsneo::Disk::MemoryType type;
|
||||
if(memTypeString == "FLASH") {
|
||||
type = icsneo::Disk::MemoryType::Flash;
|
||||
} else if(memTypeString == "SD") {
|
||||
type = icsneo::Disk::MemoryType::SD;
|
||||
} else {
|
||||
std::cout << "Incorrect memory type option" << std::endl;
|
||||
displayUsage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!device->uploadCoremini(std::make_unique<std::ifstream>(arguments[2], std::ios::binary), type)) {
|
||||
std::cout << "Failed to upload coremini" << std::endl;
|
||||
std::cout << icsneo::GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
if (!device->startScript(icsneo::Disk::MemoryType::Flash))
|
||||
{
|
||||
if (!device->startScript(type)) {
|
||||
std::cout << "Failed to start script" << std::endl;
|
||||
std::cout << icsneo::GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-interactive-example VERSION 0.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-interactive-example src/InteractiveExample.cpp)
|
||||
target_link_libraries(libicsneocpp-interactive-example icsneocpp)
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-lin VERSION 0.1.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-lin src/LINExample.cpp)
|
||||
target_link_libraries(libicsneocpp-lin icsneocpp)
|
||||
@@ -7,32 +7,6 @@
|
||||
#include "icsneo/communication/message/linmessage.h"
|
||||
|
||||
/* Note: This example requires LIN 1 and LIN 2 channels to be connected on the device */
|
||||
|
||||
char getCharInput(std::vector<char> allowed) {
|
||||
bool found = false;
|
||||
std::string input;
|
||||
|
||||
while(!found) {
|
||||
std::cin >> input;
|
||||
|
||||
if(input.length() == 1) {
|
||||
for(char compare : allowed) {
|
||||
if(compare == input.c_str()[0]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
std::cout << "Input did not match expected options. Please try again." << std::endl;
|
||||
std::cout << "<X or x to quit>" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return input.c_str()[0];
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Print version
|
||||
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl;
|
||||
@@ -46,7 +20,7 @@ int main() {
|
||||
std::cout << '\t' << device->describe() << " @ Handle " << device->getNeoDevice().handle << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
for(auto& device : devices) {
|
||||
for(auto device : devices) {
|
||||
std::cout << "Connecting to " << device->describe() << "... ";
|
||||
bool ret = device->open();
|
||||
if(!ret) { // Failed to open
|
||||
@@ -54,10 +28,54 @@ int main() {
|
||||
std::cout << icsneo::GetLastError() << std::endl << std::endl;
|
||||
continue;
|
||||
}
|
||||
std::cout << "OK" << std::endl;
|
||||
std::cout << "OK" << std::endl << std::endl;
|
||||
|
||||
int64_t baud = 19200;
|
||||
|
||||
std::cout << "Enable LIN commander resistor... ";
|
||||
ret = device->settings->setCommanderResistorFor(icsneo::Network::NetID::LIN, true);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Disable LIN2 commander resistor... ";
|
||||
ret = device->settings->setCommanderResistorFor(icsneo::Network::NetID::LIN2, false);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Setting LIN to operate at " << baud << "bit/s... ";
|
||||
ret = device->settings->setBaudrateFor(icsneo::Network::NetID::LIN, baud);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Setting LIN2 to operate at " << baud << "bit/s... ";
|
||||
ret = device->settings->setBaudrateFor(icsneo::Network::NetID::LIN2, baud);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Setting LIN mode to NORMAL... ";
|
||||
ret = device->settings->setLINModeFor(icsneo::Network::NetID::LIN, NORMAL_MODE);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Setting LIN2 mode to NORMAL... ";
|
||||
ret = device->settings->setLINModeFor(icsneo::Network::NetID::LIN2, NORMAL_MODE);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Applying settings... ";
|
||||
ret = device->settings->apply();
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "Getting LIN Baudrate... ";
|
||||
int64_t readBaud = device->settings->getBaudrateFor(icsneo::Network::NetID::LIN);
|
||||
if(readBaud < 0)
|
||||
std::cout << "FAIL" << std::endl;
|
||||
else
|
||||
std::cout << "OK, " << (readBaud) << "bit/s" << std::endl;
|
||||
|
||||
std::cout << "Getting LIN2 Baudrate... ";
|
||||
readBaud = device->settings->getBaudrateFor(icsneo::Network::NetID::LIN2);
|
||||
if(readBaud < 0)
|
||||
std::cout << "FAIL" << std::endl;
|
||||
else
|
||||
std::cout << "OK, " << (readBaud) << "bit/s" << std::endl << std::endl;
|
||||
|
||||
// The concept of going "online" tells the connected device to start listening, i.e. ACKing traffic and giving it to us
|
||||
std::cout << "\tGoing online... ";
|
||||
std::cout << "Going online... ";
|
||||
ret = device->goOnline();
|
||||
if(!ret) {
|
||||
std::cout << "FAIL" << std::endl;
|
||||
@@ -68,14 +86,14 @@ int main() {
|
||||
|
||||
// A real application would just check the result of icsneo_goOnline() rather than calling this
|
||||
// This function is intended to be called later on if needed
|
||||
std::cout << "\tChecking online status... ";
|
||||
std::cout << "Checking online status... ";
|
||||
ret = device->isOnline();
|
||||
if(!ret) {
|
||||
std::cout << "FAIL\n" << std::endl;
|
||||
device->close();
|
||||
continue;
|
||||
}
|
||||
std::cout << "OK" << std::endl;
|
||||
std::cout << "OK" << std::endl << std::endl;
|
||||
|
||||
auto handler = device->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> message) {
|
||||
if(icsneo::Message::Type::Frame == message->type) {
|
||||
@@ -95,7 +113,7 @@ int main() {
|
||||
}));
|
||||
|
||||
// We can transmit messages
|
||||
std::cout << "\tTransmitting a LIN responder data frame... ";
|
||||
std::cout << "Transmitting a LIN responder data frame... ";
|
||||
auto lin_r = std::make_shared<icsneo::LINMessage>();
|
||||
lin_r->network = icsneo::Network::NetID::LIN2;
|
||||
lin_r->ID = 0x11;
|
||||
@@ -104,7 +122,7 @@ int main() {
|
||||
ret = device->transmit(lin_r); // This will return false if the device does not support LIN
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
|
||||
std::cout << "\tTransmitting a LIN commander frame... ";
|
||||
std::cout << "Transmitting a LIN commander header... ";
|
||||
auto lin_c = std::make_shared<icsneo::LINMessage>();
|
||||
lin_c->network = icsneo::Network::NetID::LIN;
|
||||
lin_c->ID = 0x11;
|
||||
@@ -112,7 +130,9 @@ int main() {
|
||||
ret = device->transmit(lin_c);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl << std::endl;
|
||||
|
||||
std::cout << "\tTransmitting a LIN commander frame with responder data... ";
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
std::cout << "Transmitting a LIN commander frame with responder data... ";
|
||||
auto lin_d = std::make_shared<icsneo::LINMessage>();
|
||||
lin_d->network = icsneo::Network::NetID::LIN;
|
||||
lin_d->ID = 0x22;
|
||||
@@ -121,31 +141,17 @@ int main() {
|
||||
lin_d->data = {0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd};
|
||||
ret = device->transmit(lin_d);
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl << std::endl;
|
||||
std::cout << "<X or x to quit>\n\n";
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
// Go offline, stop sending and receiving traffic
|
||||
auto shutdown = [&](){
|
||||
device->removeMessageCallback(handler);
|
||||
std::cout << "\tGoing offline... ";
|
||||
std::cout << "Going offline... ";
|
||||
ret = device->goOffline();
|
||||
std::cout << (ret ? "OK" : "FAIL") << std::endl;
|
||||
std::cout << "\tDisconnecting... ";
|
||||
std::cout << "Disconnecting... ";
|
||||
ret = device->close();
|
||||
std::cout << (ret ? "OK\n" : "FAIL\n") << std::endl;
|
||||
};
|
||||
|
||||
while(true) {
|
||||
char input = getCharInput(std::vector<char> {'X', 'x'});
|
||||
switch(input) {
|
||||
case 'X':
|
||||
case 'x':
|
||||
shutdown();
|
||||
printf("Exiting program\n");
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-livedata VERSION 0.1.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-livedata src/LiveDataExample.cpp)
|
||||
target_link_libraries(libicsneocpp-livedata icsneocpp)
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-mdio VERSION 0.1.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-mdio src/MDIOExample.cpp)
|
||||
target_link_libraries(libicsneocpp-mdio icsneocpp)
|
||||
@@ -1,27 +1,2 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(libicsneocpp-simple-example VERSION 0.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 11)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Add an include directory like so if desired
|
||||
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# Enable Warnings
|
||||
if(MSVC)
|
||||
# Force to always compile with W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
else() #if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-switch -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
# Add libicsneo, usually a git submodule within your project works well
|
||||
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../third-party/libicsneo ${CMAKE_CURRENT_BINARY_DIR}/third-party/libicsneo)
|
||||
|
||||
add_executable(libicsneocpp-simple-example src/SimpleExample.cpp)
|
||||
target_link_libraries(libicsneocpp-simple-example icsneocpp)
|
||||
@@ -0,0 +1,2 @@
|
||||
add_executable(libicsneocpp-vsa-example src/VSAExample.cpp)
|
||||
target_link_libraries(libicsneocpp-vsa-example icsneocpp)
|
||||
@@ -0,0 +1,251 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
#include "icsneo/icsneocpp.h"
|
||||
|
||||
enum class MessageType {
|
||||
ShortEth,
|
||||
LongEth,
|
||||
CAN,
|
||||
CANFD
|
||||
};
|
||||
|
||||
const std::vector<std::string> MessageTypeLabels = {"short Ethernet", "long Ethernet", "CAN", "CAN-FD"};
|
||||
|
||||
void onEvent(std::shared_ptr<icsneo::APIEvent> event) {
|
||||
std::cout << event->describe() << std::endl;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<icsneo::Frame>> constructRandomFrames(size_t frameCount, MessageType frameType) {
|
||||
static constexpr size_t ClassicCANSize = 8;
|
||||
static constexpr size_t CANFDSize = 64;
|
||||
static constexpr size_t ShortEthSize = 500;
|
||||
static constexpr size_t LongEthSize = 1500;
|
||||
|
||||
std::vector<std::shared_ptr<icsneo::Frame>> frames;
|
||||
std::random_device randDev;
|
||||
std::mt19937 randEngine(randDev());
|
||||
std::uniform_int_distribution randByteDist(0,255);
|
||||
auto randByteGen = [&]() -> uint8_t {
|
||||
return static_cast<uint8_t>(randByteDist(randEngine));
|
||||
};
|
||||
|
||||
for(size_t i = 0; i < frameCount; i++) {
|
||||
switch(frameType) {
|
||||
case MessageType::ShortEth:
|
||||
// Short Ethernet
|
||||
{
|
||||
auto frame = std::make_shared<icsneo::EthernetMessage>();
|
||||
frame->network = icsneo::Network::NetID::Ethernet;
|
||||
frames.push_back(frame);
|
||||
frame->data.resize(ShortEthSize);
|
||||
std::generate(frame->data.begin(), frame->data.end(), randByteGen);
|
||||
}
|
||||
break;
|
||||
case MessageType::LongEth:
|
||||
// Long Ethernet
|
||||
{
|
||||
auto frame = std::make_shared<icsneo::EthernetMessage>();
|
||||
frame->network = icsneo::Network::NetID::Ethernet;
|
||||
frames.push_back(frame);
|
||||
frame->data.resize(LongEthSize);
|
||||
std::generate(frame->data.begin(), frame->data.end(), randByteGen);
|
||||
}
|
||||
break;
|
||||
case MessageType::CAN:
|
||||
// Classic CAN
|
||||
{
|
||||
auto frame = std::make_shared<icsneo::CANMessage>();
|
||||
frame->network = icsneo::Network::NetID::HSCAN2;
|
||||
frames.push_back(frame);
|
||||
frame->data.resize(ClassicCANSize);
|
||||
|
||||
std::generate(frame->data.begin(), frame->data.end(), randByteGen);
|
||||
}
|
||||
break;
|
||||
case MessageType::CANFD:
|
||||
// CAN FD
|
||||
{
|
||||
auto frame = std::make_shared<icsneo::CANMessage>();
|
||||
frame->network = icsneo::Network::NetID::HSCAN3;
|
||||
frames.push_back(frame);
|
||||
frame->data.resize(CANFDSize);
|
||||
std::generate(frame->data.begin(), frame->data.end(), randByteGen);
|
||||
frame->isCANFD = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
void resetScriptStatus(std::shared_ptr<icsneo::Device> rxDevice, std::shared_ptr<icsneo::Device> txDevice, bool rxInit, bool txInit) {
|
||||
if(rxInit) {
|
||||
rxDevice->startScript();
|
||||
} else {
|
||||
rxDevice->stopScript();
|
||||
}
|
||||
if(txInit) {
|
||||
txDevice->startScript();
|
||||
} else {
|
||||
txDevice->stopScript();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if(argc != 3) {
|
||||
std::cout << "Usage: libicsneocpp-vsa-example <Tx device serial> <Rx device serial>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string txSerial = argv[1];
|
||||
std::string rxSerial = argv[2];
|
||||
|
||||
// register an event callback so we can see all logged events
|
||||
icsneo::EventManager::GetInstance().addEventCallback(icsneo::EventCallback(onEvent));
|
||||
|
||||
auto devices = icsneo::FindAllDevices();
|
||||
if(devices.empty()) {
|
||||
std::cout << "error: no devices found" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::shared_ptr<icsneo::Device> txDevice;
|
||||
std::shared_ptr<icsneo::Device> rxDevice;
|
||||
for(auto&& d : devices) {
|
||||
if(txSerial == d->getSerial()) {
|
||||
txDevice = d;
|
||||
}
|
||||
if(rxSerial == d->getSerial()) {
|
||||
rxDevice = d;
|
||||
}
|
||||
}
|
||||
if(!txDevice) {
|
||||
std::cout << "error: failed to find a device with serial number: " << txSerial << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if(!rxDevice) {
|
||||
std::cout << "error: failed to find a device with serial number: " << rxSerial << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "info: found " << txDevice->describe() << std::endl;
|
||||
std::cout << "info: found " << rxDevice->describe() << std::endl;
|
||||
|
||||
if(!txDevice->open()) {
|
||||
std::cout << "error: unable to open device" << std::endl;
|
||||
}
|
||||
if(!rxDevice->open()) {
|
||||
std::cout << "error: unable to open device" << std::endl;
|
||||
}
|
||||
|
||||
const auto& rxInitialCoreminiStatus = rxDevice->getScriptStatus()->isCoreminiRunning;
|
||||
const auto& txInitialCoreminiStatus = txDevice->getScriptStatus()->isCoreminiRunning;
|
||||
|
||||
rxDevice->stopScript();
|
||||
txDevice->stopScript();
|
||||
|
||||
uint64_t origFirstOffset;
|
||||
std::shared_ptr<icsneo::VSA> origFirstRecord;
|
||||
if(!rxDevice->findFirstVSARecord(origFirstOffset, origFirstRecord)) {
|
||||
std::cout << "error: unable to find first VSA record" << std::endl;
|
||||
resetScriptStatus(rxDevice, txDevice, rxInitialCoreminiStatus, txInitialCoreminiStatus);
|
||||
return -1;
|
||||
}
|
||||
std::cout << "info: found first VSA record at " << origFirstOffset << std::endl;
|
||||
|
||||
uint64_t origLastOffset;
|
||||
std::shared_ptr<icsneo::VSA> origLastRecord;
|
||||
if(!rxDevice->findLastVSARecord(origLastOffset, origLastRecord)) {
|
||||
std::cout << "error: unable to find last VSA record" << std::endl;
|
||||
resetScriptStatus(rxDevice, txDevice, rxInitialCoreminiStatus, txInitialCoreminiStatus);
|
||||
return -1;
|
||||
}
|
||||
std::cout << "info: found last VSA record at " << origLastOffset << std::endl;
|
||||
|
||||
uint64_t canFrameCount = 0;
|
||||
uint64_t ethFrameCount = 0;
|
||||
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
|
||||
if(msg->type != icsneo::Message::Type::Frame) {
|
||||
return;
|
||||
}
|
||||
const auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
|
||||
if(frame->network.getType() == icsneo::Network::Type::CAN) {
|
||||
++canFrameCount;
|
||||
} else if(frame->network.getType() == icsneo::Network::Type::Ethernet) {
|
||||
++ethFrameCount;
|
||||
}
|
||||
}));
|
||||
icsneo::VSAExtractionSettings settings;
|
||||
{
|
||||
auto& filter = settings.filters.emplace_back();
|
||||
filter.readRange.first = origLastRecord->getTimestampICSClock() - std::chrono::seconds(20);
|
||||
filter.readRange.second = origLastRecord->getTimestampICSClock() - std::chrono::seconds(10);
|
||||
}
|
||||
{
|
||||
auto& filter = settings.filters.emplace_back();
|
||||
filter.readRange.first = origFirstRecord->getTimestampICSClock() + std::chrono::seconds(0);
|
||||
filter.readRange.second = origFirstRecord->getTimestampICSClock() + std::chrono::seconds(10);
|
||||
}
|
||||
std::cout << "info: reading two blocks of VSA, 10s from the start and 10s from the end..." << std::endl;
|
||||
if(!rxDevice->readVSA(settings)) {
|
||||
std::cout << "error: unable to read VSA" << std::endl;
|
||||
resetScriptStatus(rxDevice, txDevice, rxInitialCoreminiStatus, txInitialCoreminiStatus);
|
||||
return -1;
|
||||
}
|
||||
std::cout << "info: processed " << canFrameCount << " CAN frames and " << ethFrameCount << " Ethernet frames" << std::endl;
|
||||
|
||||
rxDevice->startScript();
|
||||
txDevice->goOnline();
|
||||
|
||||
const uint8_t NumFrameTypes = 4;
|
||||
const size_t FrameCountPerType = 2500;
|
||||
std::vector<std::shared_ptr<icsneo::Frame>> frames;
|
||||
for(uint8_t i = 0; i < NumFrameTypes; i++) {
|
||||
std::cout << "info: transmitting " << FrameCountPerType << " random " << MessageTypeLabels[i] << " frames" << std::endl;
|
||||
auto tempFrames = constructRandomFrames(FrameCountPerType, static_cast<MessageType>(i));
|
||||
frames.insert(frames.end(), tempFrames.begin(), tempFrames.end());
|
||||
if(!txDevice->transmit(tempFrames)) {
|
||||
std::cout << "error: failed to transmit frames" << std::endl;
|
||||
resetScriptStatus(rxDevice, txDevice, rxInitialCoreminiStatus, txInitialCoreminiStatus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(600));
|
||||
}
|
||||
|
||||
size_t currentMessage = 0;
|
||||
rxDevice->addMessageCallback(std::make_shared<icsneo::MessageCallback>([&](std::shared_ptr<icsneo::Message> msg) {
|
||||
if(msg->type != icsneo::Message::Type::Frame) {
|
||||
return;
|
||||
}
|
||||
auto frame = std::static_pointer_cast<icsneo::Frame>(msg);
|
||||
if(frames[currentMessage]->data == frame->data) {
|
||||
currentMessage++;
|
||||
}
|
||||
}));
|
||||
|
||||
// Read from original last frame until end of buffer
|
||||
icsneo::VSAExtractionSettings transmitSettings;
|
||||
{
|
||||
auto& filter = transmitSettings.filters.emplace_back();
|
||||
filter.readRange.first = origLastRecord->getTimestampICSClock();
|
||||
}
|
||||
|
||||
std::cout << "info: reading transmitted random frames..." << std::endl;
|
||||
if(!rxDevice->readVSA(transmitSettings)) {
|
||||
std::cout << "error: unable to read VSA" << std::endl;
|
||||
resetScriptStatus(rxDevice, txDevice, rxInitialCoreminiStatus, txInitialCoreminiStatus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "info: " << currentMessage << " transmitted frames found" << std::endl;
|
||||
resetScriptStatus(rxDevice, txDevice, rxInitialCoreminiStatus, txInitialCoreminiStatus);
|
||||
|
||||
if(currentMessage != FrameCountPerType * NumFrameTypes) {
|
||||
std::cout << "error: unable to find all transmitted frames" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
package com.example.icsneojava;
|
||||
/* ----------------------------------------------------------------------------
|
||||
* This file was automatically generated by SWIG (http://www.swig.org).
|
||||
* Version 4.0.0
|
||||
|
||||
+12
-10
@@ -49,6 +49,7 @@ public:
|
||||
ValueNotYetPresent = 0x1013,
|
||||
Timeout = 0x1014,
|
||||
WiVINotSupported = 0x1015,
|
||||
RestrictedEntryFlag = 0x1016,
|
||||
|
||||
// Device Events
|
||||
PollingMessageOverflow = 0x2000,
|
||||
@@ -104,6 +105,8 @@ public:
|
||||
LiveDataEncoderError = 0x2050,
|
||||
LiveDataDecoderError = 0x2051,
|
||||
LiveDataNotSupported = 0x2052,
|
||||
LINSettingsNotAvailable = 0x2053,
|
||||
ModeNotFound = 0x2054,
|
||||
|
||||
// Transport Events
|
||||
FailedToRead = 0x3000,
|
||||
@@ -122,11 +125,6 @@ public:
|
||||
GetIfAddrsError = 0x3108,
|
||||
SendToError = 0x3109,
|
||||
MDIOMessageExceedsMaxLength = 0x3110,
|
||||
DriverTTYPathEmpty = 0x3120,
|
||||
DriverWasNotNegOne = 0x3121,
|
||||
DriverTCGetAddrFail = 0x3122,
|
||||
DriverTCSetAddrFail = 0x3123,
|
||||
|
||||
|
||||
// FTD3XX
|
||||
FTOK = 0x4000, // placeholder
|
||||
@@ -163,15 +161,19 @@ public:
|
||||
FTIncorrectDevicePath = FTOK + 31,
|
||||
FTOtherError = FTOK + 32,
|
||||
|
||||
// Android USB
|
||||
AndroidUSBLibusbInitFailed = 0x5000,
|
||||
AndroidUSBFDWrapFailed = 0x5001,
|
||||
// VSA
|
||||
VSABufferCorrupted = 0x5000,
|
||||
VSATimestampNotFound = VSABufferCorrupted + 1,
|
||||
VSABufferFormatError = VSABufferCorrupted + 2,
|
||||
VSAMaxReadAttemptsReached = VSABufferCorrupted + 3,
|
||||
VSAByteParseFailure = VSABufferCorrupted + 4,
|
||||
VSAExtendedMessageError = VSABufferCorrupted + 5,
|
||||
VSAOtherError = VSABufferCorrupted + 6,
|
||||
|
||||
NoErrorFound = 0xFFFFFFFD,
|
||||
TooManyEvents = 0xFFFFFFFE,
|
||||
Unknown = 0xFFFFFFFF,
|
||||
Unknown = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum class Severity : uint8_t {
|
||||
Any = 0, // Used for filtering, should not appear in data
|
||||
EventInfo = 0x10,
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class Command : uint8_t {
|
||||
GetVBattReq = 0xDF, // Previously known as RED_CMD_VBATT_REQUEST
|
||||
ScriptStatus = 0xE0, // Previously known as RED_CMD_SCRIPT_STATUS
|
||||
MiscControl = 0xE7,
|
||||
NeoEraseMemory = 0xEA, // Previously known as RED_CMD_ERASE_MEMORY
|
||||
Extended = 0xF0, // Previously known as RED_CMD_EXT_COMM
|
||||
ExtendedData = 0xF2, // Previously known as RED_CMD_EXTENDED_DATA
|
||||
FlexRayControl = 0xF3,
|
||||
@@ -51,7 +52,7 @@ enum class ExtendedCommand : uint16_t {
|
||||
GetSupportedFeatures = 0x0018,
|
||||
GetComponentVersions = 0x001A,
|
||||
Reboot = 0x001C,
|
||||
SetUploadedFlag = 0x0027,
|
||||
SetRootFSEntryFlags = 0x0027,
|
||||
GenericBinaryInfo = 0x0030,
|
||||
LiveData = 0x0035,
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
bool removeMessageCallback(int id);
|
||||
std::shared_ptr<Message> waitForMessageSync(
|
||||
const std::shared_ptr<MessageFilter>& f = {},
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) {
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(500)) {
|
||||
return waitForMessageSync([](){ return true; }, f, timeout);
|
||||
}
|
||||
// onceWaitingDo is a way to avoid race conditions.
|
||||
@@ -74,7 +74,9 @@ public:
|
||||
std::shared_ptr<Message> waitForMessageSync(
|
||||
std::function<bool(void)> onceWaitingDo,
|
||||
const std::shared_ptr<MessageFilter>& f = {},
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds(500));
|
||||
|
||||
void dispatchMessage(const std::shared_ptr<Message>& msg);
|
||||
|
||||
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer;
|
||||
std::unique_ptr<Packetizer> packetizer;
|
||||
@@ -93,7 +95,6 @@ protected:
|
||||
std::mutex redirectingReadMutex; // Don't allow read to be disabled while in the redirectionFn
|
||||
std::mutex syncMessageMutex;
|
||||
|
||||
void dispatchMessage(const std::shared_ptr<Message>& msg);
|
||||
void handleInput(Packetizer& p, std::vector<uint8_t>& readBytes);
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,10 +29,10 @@ public:
|
||||
|
||||
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()))
|
||||
const auto frame = std::static_pointer_cast<RawMessage>(message);
|
||||
if(!matchNetworkType(frame->network.getType()))
|
||||
return false;
|
||||
if(!matchNetID(frame.network.getNetID()))
|
||||
if(!matchNetID(frame->network.getNetID()))
|
||||
return false;
|
||||
} else if (netid != Network::NetID::Any || networkType != Network::Type::Any) {
|
||||
return false; // Filtering on a NetID or Type, but this message doesn't have one
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace icsneo {
|
||||
|
||||
typedef uint16_t icscm_bitfield;
|
||||
|
||||
|
||||
|
||||
#pragma pack(push, 2)
|
||||
struct HardwareA2BPacket {
|
||||
|
||||
static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
|
||||
@@ -33,12 +36,21 @@ struct HardwareA2BPacket {
|
||||
icscm_bitfield : 11;
|
||||
icscm_bitfield rfu2;
|
||||
} header;
|
||||
uint8_t offset[8];
|
||||
uint16_t stats;
|
||||
struct {
|
||||
uint64_t TS : 60;
|
||||
uint64_t : 3; // Reserved for future status bits
|
||||
uint64_t IsExtended : 1;
|
||||
} timestamp;
|
||||
uint16_t networkID;
|
||||
uint16_t length;
|
||||
|
||||
static const size_t coreMiniMessageHeaderSize;
|
||||
static const size_t a2bMessageMaxLength;
|
||||
static const size_t a2bHeaderSize;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
#include "icsneo/communication/message/ethphymessage.h"
|
||||
#include "icsneo/third-party/concurrentqueue/concurrentqueue.h"
|
||||
#include "icsneo/platform/nodiscard.h"
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
#include "icsneo/disk/vsa/vsaparser.h"
|
||||
|
||||
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
|
||||
static constexpr DeviceType::Enum DEVICE_TYPE = type; \
|
||||
@@ -57,6 +59,13 @@
|
||||
#define ICSNEO_FINDABLE_DEVICE_BY_PID(className, type, pid) \
|
||||
static constexpr const uint16_t PRODUCT_ID = pid; \
|
||||
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
|
||||
|
||||
// Devices which are discernable by a serial range
|
||||
#define ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(className, type, serialLow, serialHigh) \
|
||||
static constexpr const char* SERIAL_RANGE_LOW = serialLow; \
|
||||
static constexpr const char* SERIAL_RANGE_HIGH = serialHigh; \
|
||||
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class DeviceExtension;
|
||||
@@ -148,9 +157,11 @@ public:
|
||||
int8_t prepareScriptLoad();
|
||||
bool startScript(Disk::MemoryType memType = Disk::MemoryType::SD);
|
||||
bool stopScript();
|
||||
bool clearScript();
|
||||
bool clearScript(Disk::MemoryType memType = Disk::MemoryType::SD);
|
||||
bool uploadCoremini(std::unique_ptr<std::istream>&& stream, Disk::MemoryType memType = Disk::MemoryType::SD);
|
||||
|
||||
bool eraseScriptMemory(Disk::MemoryType memType, uint64_t amount);
|
||||
|
||||
virtual std::optional<MemoryAddress> getCoreminiStartAddressFlash() const {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -413,6 +424,16 @@ public:
|
||||
IsEncrypted = 16,
|
||||
};
|
||||
|
||||
enum RootDirectoryEntryFlags : uint8_t {
|
||||
IsPrePost = 1,
|
||||
PrePostTriggered = (1 << 1),
|
||||
UploadPriority = (1 << 2) | (1 << 3),
|
||||
CellularEnabled = (1 << 4),
|
||||
WiFiEnabled = (1 << 5),
|
||||
Uploaded = (1 << 6),
|
||||
Unused = (1 << 7)
|
||||
};
|
||||
|
||||
typedef std::function< void(uint64_t value) > ScriptStatusCallback;
|
||||
|
||||
/**
|
||||
@@ -568,7 +589,19 @@ public:
|
||||
|
||||
std::optional<EthPhyMessage> sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
|
||||
|
||||
std::optional<bool> SetCollectionUploaded(uint32_t collectionEntryByteAddress);
|
||||
|
||||
/**
|
||||
* Set the flags of the root directory entry specified at given address
|
||||
*
|
||||
* Will not allow changes of IsPrePost and PrePostTriggered flags and will produce a warning
|
||||
* if there is an attempt to do so
|
||||
*
|
||||
* @param mask Flags to set, with each bit representing a different entry flag @RootDirectoryEntryFlags
|
||||
* @param values The values in which to set each flag, each bit corresponding to the flag in the same position
|
||||
* @param collectionEntryByteAddress The position of the root directory entry in which to set these flags
|
||||
* @return Success or failure
|
||||
*/
|
||||
std::optional<bool> SetRootDirectoryEntryFlags(uint8_t mask, uint8_t values, uint32_t collectionEntryByteAddress);
|
||||
|
||||
std::shared_ptr<Communication> com;
|
||||
std::unique_ptr<IDeviceSettings> settings;
|
||||
@@ -579,6 +612,103 @@ public:
|
||||
bool unsubscribeLiveData(const LiveDataHandle& handle);
|
||||
bool clearAllLiveData();
|
||||
|
||||
// VSA Read functions
|
||||
|
||||
/**
|
||||
* Read VSA message records from disk and dispatch the messages via Communication object. Default behavior excludes
|
||||
* records older than the current CoreMini script and performs a full disk dump of other records. The CoreMini script is
|
||||
* also stopped by default.
|
||||
*
|
||||
* @param extractionSettings Contains filters and other advanced settings for extraction process
|
||||
*
|
||||
* @return Returns false if there were failures during the read or parse processes or issues with record formatting, else true
|
||||
*/
|
||||
bool readVSA(const VSAExtractionSettings& extractionSettings = VSAExtractionSettings());
|
||||
|
||||
/**
|
||||
* Determines important metadata about VSA record storage on the disk. Terminates at first failed attempt to retrieve information
|
||||
*
|
||||
* @param metadata The metadata object to store the probed information into
|
||||
* @param extractionSettings The settings for this extraction of VSA data
|
||||
*
|
||||
* @return True if all metadata information was successfully found
|
||||
*/
|
||||
bool probeVSA(VSAMetadata& metadata, const VSAExtractionSettings& extractionSettings);
|
||||
|
||||
/**
|
||||
* Find the first VSA record chronologically from ring buffer in the VSA log file on disk
|
||||
*
|
||||
* @param firstOffset Variable used to pass out offset of first record on the disk
|
||||
* @param firstRecord Variable used to pass out the first record in the buffer
|
||||
* @param extractionSettings The settings for this extraction of VSA data
|
||||
* @param optMetadata Metadata about the current state of the VSA log file
|
||||
* (Must include valid CoreMini timestamp, disk size, and isOverlapped values)
|
||||
*
|
||||
* @return True if the first record was found successfully
|
||||
*/
|
||||
bool findFirstVSARecord(uint64_t& firstOffset, std::shared_ptr<VSA>& firstRecord,
|
||||
const VSAExtractionSettings& extractionSettings = VSAExtractionSettings(), std::optional<VSAMetadata> optMetadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Find the last record chronologically from ring buffer in the VSA log file with a valid timestamp
|
||||
*
|
||||
* @param lastOffset Variable used to pass out the offset of the last record on the disk
|
||||
* @param lastRecord Variable used to pass out the last record with a valid timestamp
|
||||
* @param extractionSettings The settings for this extraction of VSA data
|
||||
* @param optMetadata Metadata about the current state of the VSA log file
|
||||
* (Must include valid CoreMini timestamp, disk size, and isOverlapped values)
|
||||
*
|
||||
* @return True if the last record was found successfully
|
||||
*/
|
||||
bool findLastVSARecord(uint64_t& lastOffset, std::shared_ptr<VSA>& lastRecord,
|
||||
const VSAExtractionSettings& extractionSettings = VSAExtractionSettings(), std::optional<VSAMetadata> optMetadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Find the closest VSA record to the desired time_point
|
||||
*
|
||||
* @param point The desired time_point of the record
|
||||
* @param vsaOffset Variable used to pass out offset of record closest to the desired time_point
|
||||
* @param record Variable used to pass out the record closest to the desired time_point
|
||||
* @param extractionSettings Settings for this extraction of VSA data
|
||||
* @param optMetadata Optional param to include metadata about the VSA log file on disk
|
||||
*
|
||||
* @return Pair containing the location of the record closest to the desired time_point (in bytes from the beginning of VSA log file) and the record itself
|
||||
*/
|
||||
bool findVSAOffsetFromTimepoint(
|
||||
ICSClock::time_point point, uint64_t& vsaOffset, std::shared_ptr<VSA>& record, const VSAExtractionSettings& extractionSettings = VSAExtractionSettings(),
|
||||
std::optional<VSAMetadata> optMetadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Parse VSA message records with the given filter and dispatch them with this device's com channel
|
||||
*
|
||||
* @param metadata Important information about the VSA logfile (including first record location)
|
||||
* @param extractionSettings Settings for this extraction of VSA data
|
||||
* @param filter Struct used to determine which bytes to read and to filter out undesired VSA records
|
||||
*
|
||||
* @return True if there were no failures reading from disk, parsing VSA records, or dispatching VSA records
|
||||
*/
|
||||
bool parseVSA(
|
||||
VSAMetadata& metadata, const VSAExtractionSettings& extractionSettings = VSAExtractionSettings(),
|
||||
const VSAMessageReadFilter& filter = VSAMessageReadFilter());
|
||||
|
||||
/**
|
||||
* Wrapper function for Device::readLogicalDisk(pos, into, amount, ...) that handles the VSA record ring buffer.
|
||||
* Handles pos that is before the VSA::RecordStartOffset or is larger than the diskSize.
|
||||
* Sets amount to maximum size of ring buffer if given amount is too large.
|
||||
*
|
||||
* @param pos Position to start read from in relation to VSA file start
|
||||
* @param into The buffer to read bytes into from the disk
|
||||
* @param amount The number of bytes to read into the buffer
|
||||
* @param metadata Optional metadata param (used to determine disk size and if disk is overlapped)
|
||||
*
|
||||
* @return Returns value of return from readLogicalDisk with the given inputs
|
||||
*/
|
||||
std::optional<uint64_t> vsaReadLogicalDisk(
|
||||
uint64_t pos, uint8_t* into, uint64_t amount, std::optional<VSAMetadata> metadata = std::nullopt
|
||||
);
|
||||
|
||||
virtual bool isOnlineSupported() const { return true; }
|
||||
|
||||
protected:
|
||||
bool online = false;
|
||||
int messagePollingCallbackID = 0;
|
||||
@@ -756,6 +886,96 @@ private:
|
||||
void scriptStatusThreadBody();
|
||||
void stopScriptStatusThreadIfNecessary(std::unique_lock<std::mutex> lk);
|
||||
|
||||
// VSA Read functions
|
||||
|
||||
/**
|
||||
* Read the timestamp from disk of the VSA record stored at pos. If the timestamp is unparsable, attempt to read from
|
||||
* previous records up to minPos
|
||||
*
|
||||
* @param parser The parser that is used to create a VSA record from the given buffer
|
||||
* @param buffer Vector of bytes that stores a sector from the disk
|
||||
* @param pos The location that the buffer was read from
|
||||
* @param minPos The leftmost (minimum) offset from the beginning of the VSA log file to attempt to read from
|
||||
* @param optMetadata Optional param to include metadata about the VSA log file on disk
|
||||
*
|
||||
* @return The timestamp of the first valid record found at or before the given position
|
||||
*/
|
||||
std::optional<uint64_t> getVSATimestampOrBefore(VSAParser& parser, std::vector<uint8_t>& buffer, uint64_t pos, uint64_t minPos,
|
||||
std::optional<VSAMetadata> optMetadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Read the timestamp from disk of the VSA record stored at pos. If the timestamp is unparsable, attempt to read from
|
||||
* previous records up to maxPos
|
||||
*
|
||||
* @param parser The parser that is used to create a VSA record from the given buffer
|
||||
* @param buffer Vector of bytes that stores a sector that was previously read from the disk
|
||||
* @param pos The location that data in the buffer was read from
|
||||
* @param maxPos The rightmost (maximum) offset from the beginning of the VSA log file to attempt to read from
|
||||
* @param optMetadata Optional param to include metadata about the VSA log file on disk
|
||||
*
|
||||
* @return The timestamp of the first valid record found at or after the given position
|
||||
*/
|
||||
std::optional<uint64_t> getVSATimestampOrAfter(VSAParser& parser, std::vector<uint8_t>& buffer, uint64_t pos, uint64_t maxPos,
|
||||
std::optional<VSAMetadata> optMetadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Iterate over VSA records and dispatch the messages contained within them. For extended message records, we concatenate the payloads of all of
|
||||
* the records together before dispatching. Dispatch is performed by Communication::dispatchMessage(...).
|
||||
*
|
||||
* @param parser The parser that holds the VSAMessage records to be dispatched
|
||||
*
|
||||
* @return True if dispatching of records is successful without unhandled issues from record parse, else false
|
||||
*/
|
||||
bool dispatchVSAMessages(VSAParser& parser);
|
||||
|
||||
/**
|
||||
* Determine if the ring buffer for VSA records has filled entirely and looped to the beginning.
|
||||
*
|
||||
* @param optMetadata Optional metadata param with partial information about current state of VSA log file
|
||||
* (Must contain valid disk size and CoreMini timestamp)
|
||||
*
|
||||
* @return True if the buffer has looped; Returns std::nullopt if unable to determine
|
||||
*/
|
||||
std::optional<bool> isVSAOverlapped(std::optional<VSAMetadata> optMetadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Find the first extended message record in the sequence of the given extended message record by backtracking in the disk.
|
||||
* Results are returned by reference (not through the return value)
|
||||
*
|
||||
* @param record The extended message record whose sequence for which to find the first record
|
||||
* @param pos The position of the given record in the VSA log file (in bytes)
|
||||
* @param parser Used to parse indices and sequence numbers from the extended message records
|
||||
* @param metadata Optional param to include metadata about the VSA log file on disk
|
||||
*
|
||||
* @return True if the first extended message record in the sequence was successfully found
|
||||
*/
|
||||
bool findFirstExtendedVSAFromConsecutive(std::shared_ptr<VSAExtendedMessage>& record, uint64_t& pos,
|
||||
VSAParser& parser, std::optional<VSAMetadata> metadata = std::nullopt);
|
||||
|
||||
/**
|
||||
* Find the first record before the given position that contains a valid timestamp. Results are returned by reference.
|
||||
*
|
||||
* @param record The record from which to backtrack in the VSA buffer
|
||||
* @param pos The position of the given record in the VSA log file (in bytes)
|
||||
* @param parser Used to parse records from the VSA buffer
|
||||
*
|
||||
* @return True if a record with valid timestamp is found within a set number of reads
|
||||
*/
|
||||
bool findPreviousRecordWithTimestamp(std::shared_ptr<VSA>& record, uint64_t& pos, VSAParser& parser);
|
||||
|
||||
/**
|
||||
* Get the creation timestamp of the CoreMini script from VSA log file
|
||||
*
|
||||
* @return Timestamp in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
std::optional<uint64_t> getCoreMiniScriptTimestamp();
|
||||
|
||||
/**
|
||||
* Get the size of the VSA file storage system from the CoreMini script
|
||||
*
|
||||
* @return The size of the vsa log files on the disk
|
||||
*/
|
||||
std::optional<uint64_t> getVSADiskSize();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -536,15 +536,15 @@ enum
|
||||
BPS117647
|
||||
};
|
||||
|
||||
/* MasterResistor in LIN_SETTINGS */
|
||||
enum
|
||||
/* CommanderResistor in LIN_SETTINGS */
|
||||
enum : uint8_t
|
||||
{
|
||||
RESISTOR_ON,
|
||||
RESISTOR_OFF
|
||||
};
|
||||
|
||||
/* Mode in LIN_SETTINGS */
|
||||
enum
|
||||
enum LINMode
|
||||
{
|
||||
SLEEP_MODE,
|
||||
SLOW_MODE,
|
||||
@@ -558,7 +558,7 @@ typedef struct _LIN_SETTINGS
|
||||
uint16_t spbrg; /* Precompiled to be 40Mhz/Baudrate/16 - 1. Only used in neoVI FIRE/FIREVNET(4dw) */
|
||||
uint8_t brgh; /* Must be zero */
|
||||
uint8_t numBitsDelay;
|
||||
uint8_t MasterResistor;
|
||||
uint8_t CommanderResistor;
|
||||
uint8_t Mode;
|
||||
} LIN_SETTINGS;
|
||||
#define LIN_SETTINGS_SIZE 10
|
||||
@@ -643,6 +643,7 @@ public:
|
||||
static std::optional<uint16_t> CalculateGSChecksum(const std::vector<uint8_t>& settings, std::optional<size_t> knownSize = std::nullopt);
|
||||
static CANBaudrate GetEnumValueForBaudrate(int64_t baudrate);
|
||||
static int64_t GetBaudrateValueForEnum(CANBaudrate enumValue);
|
||||
static bool ValidateLINBaudrate(int64_t baudrate);
|
||||
|
||||
IDeviceSettings(std::shared_ptr<Communication> com, size_t size) : com(com), report(com->report), structSize(size) {}
|
||||
virtual ~IDeviceSettings() {}
|
||||
@@ -700,6 +701,16 @@ public:
|
||||
return reinterpret_cast<SWCAN_SETTINGS*>((void*)(settings.data() + (offset - settingsInDeviceRAM.data())));
|
||||
}
|
||||
|
||||
virtual const LIN_SETTINGS* getLINSettingsFor(Network net) const { (void)net; return nullptr; }
|
||||
LIN_SETTINGS* getMutableLINSettingsFor(Network net) {
|
||||
if(disabled || readonly)
|
||||
return nullptr;
|
||||
const uint8_t* offset = (const uint8_t*)getLINSettingsFor(net);
|
||||
if(offset == nullptr)
|
||||
return nullptr;
|
||||
return reinterpret_cast<LIN_SETTINGS*>((void*)(settings.data() + (offset - settingsInDeviceRAM.data())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Some devices have groupings of networks, where software
|
||||
* switchable termination can only be applied to one network
|
||||
@@ -753,6 +764,53 @@ public:
|
||||
*/
|
||||
bool setTerminationFor(Network net, bool enabled);
|
||||
|
||||
/**
|
||||
* Check whether software switchable commander resistor is currently
|
||||
* enabled for a given network in the currently active device settings.
|
||||
*
|
||||
* Returns true if the call was successful, otherwise an error
|
||||
* will have been reported in icsneo::getLastError().
|
||||
*/
|
||||
std::optional<bool> isCommanderResistorEnabledFor(Network net) const;
|
||||
|
||||
/**
|
||||
* Enable or disable software switchable commander resistor for a given
|
||||
* network.
|
||||
*
|
||||
* Returns true if the call was successful, otherwise an error
|
||||
* will have been reported in icsneo::getLastError().
|
||||
*/
|
||||
bool setCommanderResistorFor(Network net, bool resistor_on);
|
||||
|
||||
/**
|
||||
* Get LIN mode for a given network in the currently active device
|
||||
* settings.
|
||||
*/
|
||||
std::optional<enum LINMode> getLINModeFor(Network net) const;
|
||||
|
||||
/**
|
||||
* Set LIN mode for a given network.
|
||||
*
|
||||
* Returns true if the call was successful, otherwise an error
|
||||
* will have been reported in icsneo::getLastError().
|
||||
*/
|
||||
bool setLINModeFor(Network net, enum LINMode mode);
|
||||
|
||||
/**
|
||||
* Get number of bit delays between commander ID and first responder byte for
|
||||
* a given network in the currently active device settings.
|
||||
*/
|
||||
std::optional<uint8_t> getLINCommanderResponseTimeFor(Network net) const;
|
||||
|
||||
/**
|
||||
* Set number of bit delays between commander ID and first responder byte for
|
||||
* a given network
|
||||
*
|
||||
* Returns true if the call was successful, otherwise an error
|
||||
* will have been reported in icsneo::getLastError().
|
||||
*/
|
||||
bool setLINCommanderResponseTimeFor(Network net, uint8_t bits);
|
||||
|
||||
const void* getRawStructurePointer() const { return settingsInDeviceRAM.data(); }
|
||||
void* getMutableRawStructurePointer() { return settings.data(); }
|
||||
template<typename T> const T* getStructurePointer() const { return reinterpret_cast<const T*>(getRawStructurePointer()); }
|
||||
|
||||
@@ -88,6 +88,17 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<etherbadge_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -131,6 +131,23 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<neovifire_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
case Network::NetID::LIN2:
|
||||
return &(cfg->lin2);
|
||||
case Network::NetID::LIN3:
|
||||
return &(cfg->lin3);
|
||||
case Network::NetID::LIN4:
|
||||
return &(cfg->lin4);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/device/devicetype.h"
|
||||
#include "icsneo/device/tree/neovifire2/neovifire2settings.h"
|
||||
|
||||
#include "icsneo/disk/neomemorydiskdriver.h"
|
||||
namespace icsneo {
|
||||
|
||||
class NeoVIFIRE2 : public Device {
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
protected:
|
||||
NeoVIFIRE2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||
initialize<NeoVIFIRE2Settings>(makeDriver);
|
||||
initialize<NeoVIFIRE2Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
|
||||
}
|
||||
|
||||
void setupSettings(IDeviceSettings& ssettings) override {
|
||||
|
||||
@@ -209,6 +209,28 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<neovifire2_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
case Network::NetID::LIN2:
|
||||
return &(cfg->lin2);
|
||||
case Network::NetID::LIN3:
|
||||
return &(cfg->lin3);
|
||||
case Network::NetID::LIN4:
|
||||
return &(cfg->lin4);
|
||||
case Network::NetID::LIN5:
|
||||
return &(cfg->lin5);
|
||||
case Network::NetID::LIN6:
|
||||
return &(cfg->lin6);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<neovifire2_settings_t>();
|
||||
|
||||
@@ -229,6 +229,32 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<neovifire3_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
case Network::NetID::LIN2:
|
||||
return &(cfg->lin2);
|
||||
case Network::NetID::LIN3:
|
||||
return &(cfg->lin3);
|
||||
case Network::NetID::LIN4:
|
||||
return &(cfg->lin4);
|
||||
case Network::NetID::LIN5:
|
||||
return &(cfg->lin5);
|
||||
case Network::NetID::LIN6:
|
||||
return &(cfg->lin6);
|
||||
case Network::NetID::LIN7:
|
||||
return &(cfg->lin7);
|
||||
case Network::NetID::LIN8:
|
||||
return &(cfg->lin8);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<neovifire3_settings_t>();
|
||||
|
||||
@@ -212,6 +212,24 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<neovifire3flexray_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
case Network::NetID::LIN2:
|
||||
return &(cfg->lin2);
|
||||
case Network::NetID::LIN3:
|
||||
return &(cfg->lin3);
|
||||
case Network::NetID::LIN4:
|
||||
return &(cfg->lin4);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<neovifire3flexray_settings_t>();
|
||||
|
||||
@@ -170,6 +170,20 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<neovired2_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
case Network::NetID::LIN2:
|
||||
return &(cfg->lin2);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<neovired2_settings_t>();
|
||||
|
||||
@@ -33,7 +33,8 @@ typedef struct {
|
||||
struct
|
||||
{
|
||||
uint16_t hwComLatencyTestEn : 1;
|
||||
uint16_t : 15;
|
||||
uint16_t disableUsbCheckOnBoot : 1;
|
||||
uint16_t : 14;
|
||||
} flags;
|
||||
uint16_t network_enabled_on_boot;
|
||||
CAN_SETTINGS can1;
|
||||
@@ -56,11 +57,15 @@ typedef struct {
|
||||
uint32_t pwr_man_timeout;
|
||||
uint16_t pwr_man_enable;
|
||||
ETHERNET_SETTINGS2 ethernet;
|
||||
RAD_GPTP_SETTINGS gPTP;
|
||||
uint64_t network_enables_5;
|
||||
} rada2b_settings_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
static_assert(sizeof(rada2b_settings_t) == 340, "RAD-A2B settings size mismatch");
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class RADA2BSettings : public IDeviceSettings {
|
||||
@@ -84,8 +89,8 @@ public:
|
||||
};
|
||||
|
||||
enum class ChannelSize : uint8_t {
|
||||
chSize16 = 0,
|
||||
chSize32 = 1
|
||||
chSize32 = 0,
|
||||
chSize16 = 1
|
||||
};
|
||||
|
||||
enum class RADA2BDevice : uint8_t {
|
||||
@@ -121,6 +126,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<rada2b_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TDMMode getTDMMode(RADA2BDevice device) const {
|
||||
auto cfg = getStructurePointer<rada2b_settings_t>();
|
||||
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
|
||||
@@ -136,7 +153,7 @@ public:
|
||||
auto cfg = getStructurePointer<rada2b_settings_t>();
|
||||
auto &deviceSettings = device == RADA2BDevice::Monitor ? cfg->a2b_monitor : cfg->a2b_node;
|
||||
|
||||
return static_cast<ChannelSize>(~(deviceSettings.flags & a2bSettingsFlag16bit));
|
||||
return static_cast<ChannelSize>(deviceSettings.flags & a2bSettingsFlag16bit);
|
||||
}
|
||||
|
||||
uint8_t getChannelOffset(RADA2BDevice device, A2BMessage::A2BDirection dir) const {
|
||||
|
||||
@@ -3,66 +3,28 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/device/devicetype.h"
|
||||
#include "icsneo/communication/packetizer.h"
|
||||
#include "icsneo/communication/decoder.h"
|
||||
#include "icsneo/device/tree/radcomet/radcometbase.h"
|
||||
#include "icsneo/device/tree/radcomet/radcometsettings.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class RADCOMET : public Device {
|
||||
class RADComet : public RADCometBase {
|
||||
public:
|
||||
|
||||
// Serial numbers start with RC
|
||||
// USB PID is 0x1207, standard driver is FTDI3
|
||||
// Ethernet MAC allocation is 0x1D, standard driver is Raw
|
||||
ICSNEO_FINDABLE_DEVICE(RADCOMET, DeviceType::RADComet, "RC");
|
||||
ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet, DeviceType::RADComet, "RC0000", "RC0299");
|
||||
|
||||
static const std::vector<Network>& GetSupportedNetworks() {
|
||||
static std::vector<Network> supportedNetworks = {
|
||||
Network::NetID::HSCAN,
|
||||
Network::NetID::HSCAN2,
|
||||
|
||||
Network::NetID::Ethernet,
|
||||
|
||||
Network::NetID::OP_Ethernet1,
|
||||
Network::NetID::OP_Ethernet2,
|
||||
|
||||
};
|
||||
return supportedNetworks;
|
||||
std::string getProductName() const override {
|
||||
return "RAD-Comet";
|
||||
}
|
||||
|
||||
bool getEthPhyRegControlSupported() const override { return true; }
|
||||
|
||||
protected:
|
||||
RADCOMET(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||
initialize<RADCOMETSettings>(makeDriver);
|
||||
RADComet(neodevice_t neodevice, const driver_factory_t& makeDriver) : RADCometBase(neodevice) {
|
||||
initialize<RADCometSettings>(makeDriver);
|
||||
}
|
||||
|
||||
void setupPacketizer(Packetizer& packetizer) override {
|
||||
Device::setupPacketizer(packetizer);
|
||||
packetizer.disableChecksum = true;
|
||||
packetizer.align16bit = false;
|
||||
}
|
||||
|
||||
void setupEncoder(Encoder& encoder) override {
|
||||
Device::setupEncoder(encoder);
|
||||
encoder.supportCANFD = true;
|
||||
encoder.supportEthPhy = true;
|
||||
}
|
||||
|
||||
void setupDecoder(Decoder& decoder) override {
|
||||
Device::setupDecoder(decoder);
|
||||
decoder.timestampResolution = 10; // Timestamps are in 10ns increments instead of the usual 25ns
|
||||
}
|
||||
|
||||
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||
for(auto& netid : GetSupportedNetworks())
|
||||
rxNetworks.emplace_back(netid);
|
||||
}
|
||||
|
||||
// The supported TX networks are the same as the supported RX networks for this device
|
||||
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef __RADCOMET2_H_
|
||||
#define __RADCOMET2_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/device/tree/radcomet/radcometbase.h"
|
||||
#include "icsneo/device/tree/radcomet/radcometsettings.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class RADComet2 : public RADCometBase {
|
||||
public:
|
||||
|
||||
// Serial numbers start with RC, Comet2 starts at RC0300
|
||||
// USB PID is 0x1207, standard driver is FTDI3
|
||||
// Ethernet MAC allocation is 0x1D, standard driver is Raw
|
||||
ICSNEO_FINDABLE_DEVICE_BY_SERIAL_RANGE(RADComet2, DeviceType::RADComet, "RC0300", "RCZZZZ");
|
||||
|
||||
std::string getProductName() const override {
|
||||
return "RAD-Comet 2";
|
||||
}
|
||||
|
||||
const std::vector<Network>& GetSupportedNetworks() override {
|
||||
static std::vector<Network> supportedNetworks = RADCometBase::GetSupportedNetworks();
|
||||
supportedNetworks.push_back(Network::NetID::OP_Ethernet3);
|
||||
supportedNetworks.push_back(Network::NetID::MDIO4);
|
||||
return supportedNetworks;
|
||||
}
|
||||
|
||||
protected:
|
||||
RADComet2(neodevice_t neodevice, const driver_factory_t& makeDriver) : RADCometBase(neodevice) {
|
||||
initialize<RADCometSettings>(makeDriver);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifndef __RADCOMETBASE_H_
|
||||
#define __RADCOMETBASE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/device/device.h"
|
||||
#include "icsneo/device/devicetype.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
class RADCometBase : public Device {
|
||||
public:
|
||||
virtual const std::vector<Network>& GetSupportedNetworks() {
|
||||
static std::vector<Network> supportedNetworks = {
|
||||
Network::NetID::HSCAN,
|
||||
Network::NetID::HSCAN2,
|
||||
|
||||
Network::NetID::Ethernet,
|
||||
|
||||
Network::NetID::OP_Ethernet1,
|
||||
Network::NetID::OP_Ethernet2,
|
||||
|
||||
Network::NetID::LIN,
|
||||
Network::NetID::ISO9141,
|
||||
|
||||
Network::NetID::MDIO1,
|
||||
Network::NetID::MDIO2,
|
||||
Network::NetID::MDIO3,
|
||||
};
|
||||
return supportedNetworks;
|
||||
}
|
||||
|
||||
bool getEthPhyRegControlSupported() const override { return true; }
|
||||
|
||||
protected:
|
||||
using Device::Device;
|
||||
|
||||
void setupPacketizer(Packetizer& packetizer) override {
|
||||
Device::setupPacketizer(packetizer);
|
||||
packetizer.disableChecksum = true;
|
||||
packetizer.align16bit = false;
|
||||
}
|
||||
|
||||
void setupEncoder(Encoder& encoder) override {
|
||||
Device::setupEncoder(encoder);
|
||||
encoder.supportCANFD = true;
|
||||
encoder.supportEthPhy = true;
|
||||
}
|
||||
|
||||
void setupDecoder(Decoder& decoder) override {
|
||||
Device::setupDecoder(decoder);
|
||||
decoder.timestampResolution = 10; // Timestamps are in 10ns increments instead of the usual 25ns
|
||||
}
|
||||
|
||||
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
|
||||
for(auto& netid : GetSupportedNetworks())
|
||||
rxNetworks.emplace_back(netid);
|
||||
}
|
||||
|
||||
// The supported TX networks are the same as the supported RX networks for this device
|
||||
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
|
||||
|
||||
std::optional<MemoryAddress> getCoreminiStartAddressFlash() const override {
|
||||
return 32*1024*1024;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif
|
||||
@@ -54,6 +54,8 @@ typedef struct {
|
||||
// 10T1S
|
||||
ETHERNET_SETTINGS2 ethT1s2;
|
||||
ETHERNET10T1S_SETTINGS t1s2;
|
||||
uint64_t network_enables_5;
|
||||
LIN_SETTINGS lin1;
|
||||
} radcomet_settings_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -61,9 +63,9 @@ typedef struct {
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class RADCOMETSettings : public IDeviceSettings {
|
||||
class RADCometSettings : public IDeviceSettings {
|
||||
public:
|
||||
RADCOMETSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radcomet_settings_t)) {}
|
||||
RADCometSettings(std::shared_ptr<Communication> com) : IDeviceSettings(com, sizeof(radcomet_settings_t)) {}
|
||||
const CAN_SETTINGS* getCANSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radcomet_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
|
||||
@@ -170,6 +170,18 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radgalaxy_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
|
||||
protected:
|
||||
RADGigastar(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||
initialize<RADGigastarSettings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
|
||||
initialize<RADGigastarSettings>(makeDriver);
|
||||
}
|
||||
|
||||
void setupPacketizer(Packetizer& packetizer) override {
|
||||
|
||||
@@ -149,6 +149,18 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radgigastar_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<radgigastar_settings_t>();
|
||||
|
||||
@@ -118,6 +118,17 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radjupiter_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -170,6 +170,18 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radmars_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<radmars_settings_t>();
|
||||
|
||||
@@ -64,6 +64,8 @@ public:
|
||||
|
||||
virtual uint8_t getPhyAddrOrPort() const = 0;
|
||||
|
||||
bool isOnlineSupported() const override { return false; }
|
||||
|
||||
protected:
|
||||
using Device::Device;
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
|
||||
bool getEthPhyRegControlSupported() const override { return true; }
|
||||
|
||||
bool isOnlineSupported() const override { return false; }
|
||||
|
||||
protected:
|
||||
RADMoon3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||
initialize<RADMoon3Settings>(makeDriver);
|
||||
|
||||
@@ -104,6 +104,18 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radpluto_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -99,6 +99,18 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<radstar2_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,18 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
|
||||
@@ -37,6 +37,18 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,18 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
if(cfg == nullptr)
|
||||
return nullptr;
|
||||
switch(net.getNetID()) {
|
||||
case Network::NetID::LIN:
|
||||
return &(cfg->lin1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
ICSNEO_UNALIGNED(const uint64_t*) getTerminationEnables() const override {
|
||||
auto cfg = getStructurePointer<valuecan4_4_2el_settings_t>();
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isOnlineSupported() const override { return false; }
|
||||
|
||||
protected:
|
||||
VividCAN(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
|
||||
initialize<VividCANSettings>(makeDriver);
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
#ifndef __VSA_H__
|
||||
#define __VSA_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/communication/network.h"
|
||||
#include "icsneo/communication/packet.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include "stdint.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
using CaptureBitfield = uint16_t;
|
||||
|
||||
static constexpr uint64_t ICSEpochHoursSinceUnix = 13514 * 24; // Number of hours between the start of the Unix epoch and the start of the ICS epoch
|
||||
static constexpr uint64_t UINT63_MAX = 0x7FFFFFFFFFFFFFFFu;
|
||||
|
||||
/**
|
||||
* Struct that meets Clock format requirements from STL Chrono library.
|
||||
* Indicates time for for the ICS Epoch (January 1, 2007) in 25 nanosecond ticks.
|
||||
*/
|
||||
struct ICSClock {
|
||||
using rep = uint64_t; // Type for tick count
|
||||
using period = std::ratio_multiply<std::ratio<25>, std::nano>; // Ratio of tick length to seconds (25 nanoseconds)
|
||||
using duration = std::chrono::duration<rep, period>; // Type for duration in 25 nanosecond ticks
|
||||
using time_point = std::chrono::time_point<ICSClock>; // Type for a point in time with respect to ICSClock
|
||||
|
||||
static constexpr bool is_steady = true; // This clock does not move backwards
|
||||
|
||||
/**
|
||||
* Get the time_point at the current time with respect to ICSClock
|
||||
*
|
||||
* @return Time point at the current time with respect to ICSClock
|
||||
*/
|
||||
static time_point now() noexcept
|
||||
{
|
||||
return time_point { std::chrono::duration_cast<duration>(std::chrono::system_clock::now().time_since_epoch()) -
|
||||
std::chrono::hours(ICSEpochHoursSinceUnix) };
|
||||
}
|
||||
};
|
||||
|
||||
using Timestamp = ICSClock::time_point; // Point in time to start or stop read
|
||||
|
||||
class VSA;
|
||||
|
||||
/**
|
||||
* Holds metadata for the VSA log file
|
||||
*/
|
||||
struct VSAMetadata {
|
||||
uint64_t firstRecordLocation = UINT64_MAX; // Location of the record with lowest timestamp in ring buffer
|
||||
std::shared_ptr<VSA> firstRecord = nullptr; // The record with lowest timestamp
|
||||
uint64_t lastRecordLocation = UINT64_MAX; // Location of the record with the highest timestamp in ring buffer
|
||||
std::shared_ptr<VSA> lastRecord = nullptr; // The record with the highest timestamp
|
||||
uint64_t bufferEnd = UINT64_MAX; // One byte beyond the last byte of the sequence started from lastRecordLocation
|
||||
uint64_t diskSize = 0; // The size of the vsa log file on the disk
|
||||
bool isOverlapped = false; // Determines if VSA ring buffer has looped to beginning
|
||||
uint64_t coreMiniTimestamp = UINT64_MAX; // Timestamp of the CoreMini message in 25 nanosecond ticks since January 1, 2007
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct used to exclude VSA message records from parse
|
||||
*/
|
||||
struct VSAMessageReadFilter {
|
||||
CaptureBitfield captureBitfield = UINT16_MAX; // The capture from which to gather VSA message records. UINT16_MAX indicates 'all captures'
|
||||
|
||||
// The range of timestamps to collect record data from
|
||||
std::pair<Timestamp, Timestamp> readRange = std::make_pair(Timestamp(ICSClock::duration(0x0ull)), Timestamp(ICSClock::duration(UINT64_MAX)));
|
||||
|
||||
static constexpr Timestamp MinTimestamp = Timestamp(ICSClock::duration(0x0ull));
|
||||
static constexpr Timestamp MaxTimestamp = Timestamp(ICSClock::duration(UINT64_MAX));
|
||||
};
|
||||
|
||||
struct VSAExtractionSettings {
|
||||
bool parseOldRecords = false;
|
||||
bool stopCoreMini = true;
|
||||
std::vector<VSAMessageReadFilter> filters;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract VSA base class to store VSA record data read from VSA log file on disk
|
||||
*/
|
||||
class VSA {
|
||||
public:
|
||||
virtual ~VSA() = default;
|
||||
static constexpr size_t StandardRecordSize = 32; // Size of most VSA records
|
||||
static constexpr uint64_t RecordStartOffset = 0x06000000u; // Offset of VSA record ring buffer from start of VSA log file
|
||||
|
||||
/**
|
||||
* Convert the given time_point object to a timestamp in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return Timestamp of the given time_point in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
static uint64_t getICSTimestampFromTimepoint(const Timestamp& point) noexcept { return point.time_since_epoch().count(); }
|
||||
|
||||
/**
|
||||
* Enum to determine what type of record is underlying VSA parent class
|
||||
*/
|
||||
enum class Type : uint16_t {
|
||||
AA00 = 0xAA00u, // Pad
|
||||
AA01 = 0xAA01u, // Message Data (Deprecated)
|
||||
AA02 = 0xAA02u, // 'Logdata'
|
||||
AA03 = 0xAA03u, // Event
|
||||
AA04 = 0xAA04u, // Partition Info
|
||||
AA05 = 0xAA05u, // Application Error
|
||||
AA06 = 0xAA06u, // Internal/Debug
|
||||
AA07 = 0xAA07u, // Internal/Debug
|
||||
AA08 = 0xAA08u, // Buffer Info
|
||||
AA09 = 0xAA09u, // Device Info
|
||||
AA0A = 0xAA0Au, // Logger Configuration Info (Deprecated)
|
||||
AA0B = 0xAA0Bu, // Message Data
|
||||
AA0C = 0xAA0Cu, // PCM Audio Data
|
||||
AA0D = 0XAA0Du, // Message Data (Extended)
|
||||
AA0E = 0xAA0Eu, // Message Data (Extended)
|
||||
AA0F = 0xAA0Fu, // Message Data (Extended)
|
||||
AA6A = 0xAA6Au, // Logger Configuration Backup (512 Bytes)
|
||||
Invalid = UINT16_MAX // Used to indicate unset or unhandled VSA record types
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the record type
|
||||
*
|
||||
* @return Type of record
|
||||
*/
|
||||
Type getType() const { return type; }
|
||||
|
||||
/**
|
||||
* Get the timestamp stored in this record
|
||||
*
|
||||
* @return The record's timestamp in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
virtual uint64_t getTimestamp() = 0;
|
||||
|
||||
/**
|
||||
* Determine whether this record has a valid timestamp. All invalid timestamps are set to the maximum value for a uint64_t.
|
||||
*
|
||||
* @return True if the timestamp is set to a valid number
|
||||
*/
|
||||
bool isTimestampValid() { return getTimestamp() != UINT64_MAX && !checksumFailed; }
|
||||
|
||||
/**
|
||||
* Determine if the checksum for this record failed
|
||||
*
|
||||
* @return True if the checksum does not pass
|
||||
*/
|
||||
bool getChecksumFailed() { return checksumFailed; }
|
||||
|
||||
/**
|
||||
* Get the timestamp of this record in C++ native std::chrono::time_point
|
||||
*
|
||||
* @return Timestamp of record as an std::chrono::time_point
|
||||
*/
|
||||
Timestamp getTimestampICSClock()
|
||||
{
|
||||
return Timestamp(std::chrono::duration_cast<ICSClock::duration>(std::chrono::nanoseconds(getTimestamp() * 25)));
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Used to construct a VSA record from child class
|
||||
*/
|
||||
VSA() {}
|
||||
|
||||
/**
|
||||
* Used to set the type of this record in child class constructors
|
||||
*
|
||||
* @param recordType The type of this record
|
||||
*/
|
||||
void setType(Type recordType) { this->type = recordType; }
|
||||
|
||||
/**
|
||||
* Set whether the checksum was passed for this record. This is called in each child class constructor.
|
||||
*
|
||||
* @param fail True if checksum did not pass, else false
|
||||
*/
|
||||
void setChecksumFailed(bool fail) { checksumFailed = fail; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Performs checksum on data in specific record type. Calls VSA::setChecksumFailed(...) from child class.
|
||||
*
|
||||
* @param recordBytes Bytestream of record to perform checksum with
|
||||
*/
|
||||
virtual void doChecksum(uint8_t* recordBytes) = 0;
|
||||
|
||||
Type type = Type::Invalid; // The type of this record
|
||||
bool checksumFailed = false; // Determines if checksum failed
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface class for handling common functionality of VSAMessage record types (AA0B, AA0D, AA0E, AA0F)
|
||||
*/
|
||||
class VSAMessage : public VSA {
|
||||
public:
|
||||
static constexpr size_t CoreMiniPayloadSize = 24; // Size of CoreMini message (payload)
|
||||
|
||||
/**
|
||||
* Construct a packet from the message payload and network
|
||||
*
|
||||
* @return Packet constructed from payload and network
|
||||
*/
|
||||
std::shared_ptr<Packet> getPacket() const;
|
||||
|
||||
/**
|
||||
* Reserve enough memory to store a CoreMini message in the given packet
|
||||
*
|
||||
* @param packet The packet in which we are reserving memory for a message
|
||||
*/
|
||||
virtual void reservePacketData(std::shared_ptr<Packet>& packet) const { packet->data.reserve(CoreMiniPayloadSize); }
|
||||
|
||||
/**
|
||||
* Determine whether to filter out this VSAMessage record during parsing
|
||||
*
|
||||
* @param filter The filter struct to check this message record against
|
||||
*
|
||||
* @return True if this message passes the given filter
|
||||
*/
|
||||
virtual bool filter(const std::shared_ptr<VSAMessageReadFilter> filter) = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor for normal instance of VSAMessage class
|
||||
*
|
||||
* @param messageBytes Bytestream that begins at the start of the message payload
|
||||
* @param numBytes The number of bytes that the message payload contains
|
||||
* @param networkId The CoreMini ID of the network for this message
|
||||
*/
|
||||
VSAMessage(uint8_t* const messageBytes, size_t numBytes, Network::CoreMini networkId = static_cast<Network::CoreMini>(UINT16_MAX))
|
||||
: VSA(), payload(messageBytes, messageBytes + numBytes), network(networkId) {}
|
||||
|
||||
std::vector<uint8_t> payload; // CoreMini message/payload of VSA record containing message data
|
||||
Network network; // CoreMini network of this message
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface class for handling common functionality of VSA Extended Message records (AA0D, AA0E, AA0F)
|
||||
*/
|
||||
class VSAExtendedMessage : public VSAMessage {
|
||||
public:
|
||||
static void truncatePacket(std::shared_ptr<Packet> packet);
|
||||
|
||||
/**
|
||||
* Appends the payload for this message to the given packet.
|
||||
* Also sets the network of the packet if unset (used primarily for AA0F records which do not contain the network in the first extended message record).
|
||||
*
|
||||
* @param packet The packet to append this record's payload to
|
||||
*/
|
||||
void appendPacket(std::shared_ptr<Packet> packet) const;
|
||||
|
||||
/**
|
||||
* Get the total number of records for this extended message
|
||||
*
|
||||
* @return Total number of records that this message spans
|
||||
*/
|
||||
uint32_t getRecordCount() const { return totalRecordCount; }
|
||||
|
||||
/**
|
||||
* Get the index of this record in the extended message sequence
|
||||
*
|
||||
* @return The index of this record
|
||||
*/
|
||||
uint16_t getIndex() { return index; };
|
||||
|
||||
/**
|
||||
* Get the numerical id of the sequence of extended message records this record is a part of
|
||||
*
|
||||
* @return The sequence number of this extended message record
|
||||
*/
|
||||
uint16_t getSequenceNum() { return sequenceNum; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor for normal instance of VSAExtendedMessage
|
||||
*
|
||||
* @param messageBytes Bytestream that begins at the start of the message payload
|
||||
* @param numBytes The length of the message payload in bytes
|
||||
* @param networkId The CoreMini ID of the network for this message
|
||||
*/
|
||||
VSAExtendedMessage(uint8_t* const messageBytes, size_t numBytes, Network::CoreMini networkId = static_cast<Network::CoreMini>(UINT16_MAX))
|
||||
: VSAMessage(messageBytes, numBytes, networkId) {}
|
||||
|
||||
/**
|
||||
* Set the total number of records for this message
|
||||
*
|
||||
* @param recordCount Total number of records for this message
|
||||
*/
|
||||
void setRecordCount(uint32_t recordCount) { totalRecordCount = recordCount; }
|
||||
|
||||
/**
|
||||
* Set the index of this record
|
||||
*
|
||||
* @param recordIndex The index of this record in its extended message sequence
|
||||
*/
|
||||
void setIndex(uint16_t recordIndex) { this->index = recordIndex; }
|
||||
|
||||
/**
|
||||
* Set the sequence number of this record
|
||||
*
|
||||
* @param seq The id for the extended message sequence this record is a part of
|
||||
*/
|
||||
void setSequenceNum(uint16_t seq) { sequenceNum = seq; }
|
||||
|
||||
private:
|
||||
uint32_t totalRecordCount; // The total number of records for the extended message
|
||||
uint16_t index; // The index of this record in its extended message sequence
|
||||
uint16_t sequenceNum; // The id of the sequence of records this record is a part of
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA_H__
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef __VSA02_H__
|
||||
#define __VSA02_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class that contains data for Logdata records
|
||||
*/
|
||||
class VSA02 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor that parses the given bytestream
|
||||
*
|
||||
* @param bytes Bystream that contains data for Logdata VSA records
|
||||
*/
|
||||
VSA02(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum for this record
|
||||
*
|
||||
* @param bytes Bystream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint16_t constantIndex; // Index into CoreMini binary where constant data for this record can be found
|
||||
struct Flags {
|
||||
bool hasMoreData : 1; // Set to true if there are further Logdata records expected to terminate this "chain"
|
||||
uint8_t numSamples : 3; // Number of valid samples in samples
|
||||
bool isAscii : 1; // Set to true if the processing code should treat samples as an ASCII string
|
||||
bool prefixTime : 1; // Set to true if the function block step that created this record requested that the timestamp be prepended on the output
|
||||
bool sample0IsHex : 1; // Set to true if the value in sample 0 should be written as hex
|
||||
bool sample1IsHex : 1; // Set to true if the value in sample 1 shoudl be written as hex
|
||||
} flags; // Series of flags for this record
|
||||
uint8_t pieceCount; // Value of the rolling counter for this "chain" of logdata records
|
||||
uint64_t timestamp; // Timestamp in 25 nanosecond ticks since January 1, 2007
|
||||
std::vector<uint8_t> samples; // Data for this record that varies based on the above flags. Either 2 32.32 fixed point values or 16 byte ASCII string
|
||||
uint16_t checksum; // The sum of the previous 15 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA02_H__
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef __VSA03_H__
|
||||
#define __VSA03_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class used to store event
|
||||
*/
|
||||
class VSA03 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor that extracts data from the given bytestream
|
||||
*
|
||||
* @param bytes Bytestream to extract VSA record data from
|
||||
*/
|
||||
VSA03(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform checksum for this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
enum class EventType : uint16_t {
|
||||
CaptureStarted = 0,
|
||||
StorageReconnected = 3,
|
||||
FileSystemBufferOverflow = 4,
|
||||
LoggerWentToSleep = 5,
|
||||
Internal = 7,
|
||||
CaptureStopped = 8,
|
||||
LoggerPowerEvent = 9
|
||||
} eventType; // Enumerated value indicating which type of event occurred
|
||||
uint16_t eventData; // Information about the event that is dependent on eventType
|
||||
uint64_t timestamp; // Timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // The sum of the previous 7 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA03_H__
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef __VSA04_H__
|
||||
#define __VSA04_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class that contains a partition info record
|
||||
*/
|
||||
class VSA04 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor that created partition info record from bytestream
|
||||
*
|
||||
* @param bytes Bytestream to create this record from
|
||||
*/
|
||||
VSA04(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return Timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum for this record
|
||||
*
|
||||
* @param bytes Bytestream to check against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
struct Flags {
|
||||
bool invalidRequestDetected : 1; // Indicates if an invalid request was detected
|
||||
uint16_t reserved : 15; // Empty flag bits
|
||||
} flags; // Mostly empty field for flags
|
||||
uint16_t partitionIndex; // The index of the partition containing this record
|
||||
uint64_t timestamp; // Timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // Sum of the previous 7 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA04_H__
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef __VSA05_H__
|
||||
#define __VSA05_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class that holds data for application error records
|
||||
*/
|
||||
class VSA05 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor to convert bytestream into application error record
|
||||
*
|
||||
* @param bytes The bytestream containing the record data
|
||||
*/
|
||||
VSA05(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
enum class ErrorType : uint16_t {
|
||||
NetworkReceiveBufferOverflow = 0,
|
||||
NetworkTransmitBufferOverflow = 1,
|
||||
NetworkTransmitReportBufferOverflow = 2,
|
||||
PeripheralProcessorCommunicationError = 3,
|
||||
NetworkPeripheralOverflow = 4,
|
||||
CommunicationPacketChecksumError = 6,
|
||||
CommunicationPacketDetectedMissingByte = 7,
|
||||
FailedToApplySettingsToNetwork = 9,
|
||||
EnabledNetworkCountExceedsLicenseCapability = 10,
|
||||
NetworkNotEnabled = 11,
|
||||
DetectedInvalidTimestamp = 12,
|
||||
LoadedDefaultSettings = 13,
|
||||
DeviceAttemptedUnsupportedOperation = 14,
|
||||
TrasmitBufferFillExceededThreshold = 17,
|
||||
TransmitRequestedOnInvalidNetwork = 18,
|
||||
TransmitRequestedOnTransmitIncapableNetwork = 19,
|
||||
TransmitRequestedWhileControllersInactive = 20,
|
||||
FilterMatchesExceedLimit = 21,
|
||||
EthernetPreemptionError = 22,
|
||||
TransmitWhileControllerModeInvalid = 23,
|
||||
FragmentedEthernetIPFrame = 25,
|
||||
TransmitBufferUnderrun = 26,
|
||||
ActiveCoolingFailureDetected = 27,
|
||||
OvertemperatureConditionDetected = 28,
|
||||
UndersizedEthernetFrame = 30,
|
||||
OversizedEthernetFrame = 31,
|
||||
SystemWatchdogEventOcurred = 32,
|
||||
SystemClockFailureDetected = 33,
|
||||
RecoveredFromSystemClockFailure = 34,
|
||||
SystemResetFailedPeripheralComponent = 35,
|
||||
FailedToInitializeLoggerDisk = 41,
|
||||
AttemptedToApplyInvalidSettingsToNetwork = 42
|
||||
} errorType; // Enumerated value indicating the type of error that occurred
|
||||
uint16_t errorNetwork; // When applicable, the enumerated network index that the error occurred on
|
||||
uint64_t timestamp; // Timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // Sum of the previous 7 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA05_H__
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef __VSA06_H__
|
||||
#define __VSA06_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class that holds data for an internal/debug VSA record
|
||||
*/
|
||||
class VSA06 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor to convert bytestream into internal/debug record
|
||||
*
|
||||
* @param bytes Bytestream to parse into internal/debug record
|
||||
*/
|
||||
VSA06(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
std::vector<uint32_t> savedSectors; // Unknown
|
||||
uint16_t error; // Unknown
|
||||
uint16_t savedSectorsHigh; // Unknown
|
||||
uint64_t timestamp; // Timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // Sum of the previous 15 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA06_H__
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef __VSA07_H__
|
||||
#define __VSA07_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class that holds data for an internal/debug VSA record
|
||||
*/
|
||||
class VSA07 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor to convert bytestream into internal/debug record
|
||||
*
|
||||
* @param bytes Bytestream to parse into internal/debug record
|
||||
*/
|
||||
VSA07(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint32_t lastSector; // Unknown
|
||||
uint32_t currentSector; // Unknown
|
||||
std::vector<uint8_t> reserved; // Unused bytes (12 bytes)
|
||||
uint64_t timestamp; // Timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // Sum of the previous 15 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA07_H__
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef __VSA08_H__
|
||||
#define __VSA08_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class to store data for a buffer information record
|
||||
*/
|
||||
class VSA08 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor to convert a bytestream to a buffer info record
|
||||
*
|
||||
* @param bytes Bytestream to convert into a buffer record
|
||||
*/
|
||||
VSA08(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
std::vector<uint8_t> troubleSramCount; // Unknown (4 bytes)
|
||||
std::vector<uint32_t> troubleSectors; // Unknown (16 bytes)
|
||||
uint64_t timestamp; // Timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // Sum of the previous 15 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA08_H__
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef __VSA09_H__
|
||||
#define __VSA09_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class used to store data for a Device Information VSA Record
|
||||
*/
|
||||
class VSA09 : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor to convert bytestream to Device Information VSA Record
|
||||
*
|
||||
* @param bytes Bytestream to convert into Device Information Record
|
||||
*/
|
||||
VSA09(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint32_t serialNumber; // Decimal representation of Base-36 serial number
|
||||
uint8_t firmwareMajorVersion; // Major version of firmware (A for A.B version)
|
||||
uint8_t firmwareMinorVersion; // Minor version of firmware (B for A.B version)
|
||||
uint8_t manufactureMajorRevision; // Major version of manufacture revision (A for A.B revision)
|
||||
uint8_t manufactureMinorRevision; // Minor version of manufacture revision (B for A.B revision)
|
||||
uint8_t bootloaderMajorVersion; // Major version of bootloader (A for A.B version)
|
||||
uint8_t bootloaderMinorVersion; // Minor version of bootloader (B for A.B version)
|
||||
std::vector<uint8_t> reserved0; // Unused bytes (6 bytes)
|
||||
enum class HardwareID : uint8_t {
|
||||
NeoVIRED = 0,
|
||||
NeoVIFIRE = 1,
|
||||
NeoVIION = 11,
|
||||
RADGalaxy = 19,
|
||||
RADMars = 29,
|
||||
ValueLOG = 31,
|
||||
NeoVIRED2FIRE3 = 33,
|
||||
RADGigastar = 36
|
||||
} hardwareID; // Identifier for specific hardware device type
|
||||
std::vector<uint8_t> reserved1; // Unused bytes (3 bytes)
|
||||
uint64_t timestamp; // Timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
uint16_t checksum; // Sum of the previous 15 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA09_H__
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef __VSA0B_H__
|
||||
#define __VSA0B_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <vector>
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class that holds single-record message records
|
||||
*/
|
||||
class VSA0B : public VSAMessage {
|
||||
public:
|
||||
/**
|
||||
* Constructor that reads message record data from bytestream
|
||||
*
|
||||
* @param bytes Bytestream to read message record data from
|
||||
*/
|
||||
VSA0B(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Determine whether to filter out this message record
|
||||
*
|
||||
* @param filter The filter to check this record against
|
||||
*
|
||||
* @return True if this record has passed the filter (i.e., is not being filtered out)
|
||||
*/
|
||||
bool filter(const std::shared_ptr<VSAMessageReadFilter> filter) override;
|
||||
|
||||
/**
|
||||
* Get the timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return Timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform a checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint16_t captureBitfield; // The capture that this record is a part of
|
||||
uint8_t reserved; // Unused bytes
|
||||
uint16_t checksum; // Sum of the previous 15 half words
|
||||
|
||||
uint64_t timestamp; // Timestamp of this record in 25 nanosecond ticks since January 1, 2007 (extracted from CoreMini message payload)
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA0B_H__
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef __VSA0C_H__
|
||||
#define __VSA0C_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Class used to hold data for a PCM Audio VSA Record
|
||||
*/
|
||||
class VSA0C : public VSA {
|
||||
public:
|
||||
/**
|
||||
* Constructor to convert bytestream to PCM Audio Record
|
||||
*
|
||||
* @param bytes Bytestream to parse
|
||||
*/
|
||||
VSA0C(uint8_t* const bytes);
|
||||
|
||||
/**
|
||||
* Get the timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*
|
||||
* @return The timestamp for this record in 25 nanosecond ticks since January 1, 2007
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform the checksum on this record
|
||||
*
|
||||
* @param bytes Bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint16_t captureBitfield; // Capture this record is a member of (Unused)
|
||||
uint8_t audioPreamble; // Unknown
|
||||
uint8_t audioHeader; // Unknown
|
||||
std::vector<uint8_t> pcmData; // Audio data payload (14 bytes)
|
||||
uint64_t timestamp; // Timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
struct VNet {
|
||||
uint16_t vNetSlot : 2; // Bits to identify VNet slot of this record
|
||||
uint16_t reserved : 14; // Unused bits
|
||||
} vNetBitfield; // Struct to ensure VNetSlot is only 2 bits
|
||||
uint16_t checksum; // Sum of the previous 15 words
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // __VSA0C_H__
|
||||
@@ -0,0 +1,135 @@
|
||||
#ifndef __VSA0D_H__
|
||||
#define __VSA0D_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "icsneo/disk/vsa/vsa.h"
|
||||
|
||||
namespace icsneo {
|
||||
|
||||
/**
|
||||
* Base class for VSA0D extended message record types
|
||||
*/
|
||||
class VSA0D : public VSAExtendedMessage {
|
||||
public:
|
||||
/**
|
||||
* Constructor for VSA0D parent class. Passes most information to VSAExtendedMessage constructor.
|
||||
*
|
||||
* @param bytes Bytestream to read record data from
|
||||
* @param messageBytes Bytestream starting at the payload of this message record
|
||||
* @param numBytes The length of the payload of this message record
|
||||
* @param runningChecksum Checksum for the payload bytes of this sequence of extended message records
|
||||
* @param networkId The CoreMini Network ID for this record
|
||||
*/
|
||||
VSA0D(uint8_t* const bytes, uint8_t* const messageBytes, size_t numBytes, uint32_t& runningChecksum, Network::CoreMini networkId = static_cast<Network::CoreMini>(0xFFFFu));
|
||||
};
|
||||
|
||||
/**
|
||||
* Class holding data for the first record in a series of VSA0D extended message records
|
||||
*/
|
||||
class VSA0DFirst : public VSA0D {
|
||||
public:
|
||||
/**
|
||||
* Constructor that parses first 32 bytes of bytestream into readable data.
|
||||
*
|
||||
* @param bytes Bytestream to parse VSA record from
|
||||
*/
|
||||
VSA0DFirst(uint8_t* const bytes, uint32_t& runningChecksum);
|
||||
|
||||
/**
|
||||
* Reserve memory in the packet data vector to store message data from this record and subsequent consecutive records.
|
||||
*
|
||||
* @param packet The packet to reserve memory in
|
||||
*/
|
||||
void reservePacketData(std::shared_ptr<Packet>& packet) const override;
|
||||
|
||||
/**
|
||||
* Determine whether to filter out this message record
|
||||
*
|
||||
* @param filter The filter to check this record against
|
||||
*
|
||||
* @return True if the record passes the filter
|
||||
*/
|
||||
bool filter(const std::shared_ptr<VSAMessageReadFilter> filter) override;
|
||||
|
||||
/**
|
||||
* Get the timestamp of this record. Timestamp indicates number of 25 nanosecond ticks since January 1, 2007.
|
||||
*
|
||||
* @return The timestamp of this record
|
||||
*/
|
||||
uint64_t getTimestamp() override { return timestamp; }
|
||||
|
||||
/**
|
||||
* Reorder bytes in the payload between this record and the second record in the sequence. The bytes are reordered to allow
|
||||
* simple concatenation of payload bytes from records before creating and dispatching a packet.
|
||||
*
|
||||
* @param secondPayload Reference to the payload from the second record in the sequence
|
||||
*/
|
||||
void reorderPayload(std::vector<uint8_t>& secondPayload);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform checksum on this record with the given bytestream
|
||||
*
|
||||
* @param bytes The bytestream to test against the checksum
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint16_t captureBitfield; // The data capture this record is a part of
|
||||
uint64_t timestamp; // The timestamp of this record in 25 nanosecond ticks since January 1, 2007
|
||||
struct VNet {
|
||||
uint8_t vNetSlot : 2; // VNet bytes
|
||||
uint8_t reserved : 6; // Unused bytes
|
||||
} vNetInfo; // Struct used to indicate which bytes are actually used for VNetSlot
|
||||
uint16_t checksum; // The sum of the previous 15 words
|
||||
bool timestampIsExtended = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class holding data for subsequent records in series of VSA0D extended message records
|
||||
*/
|
||||
class VSA0DConsecutive : public VSA0D {
|
||||
public:
|
||||
/**
|
||||
* Constructor that parses first 32 bytes of VSA0D record
|
||||
* @param bytes Bytestream to read VSA record data from
|
||||
* @param first The first record in this series of VSA0D records
|
||||
* @param isLastRecord Determines if this record is the last record in this series of extended message records
|
||||
*/
|
||||
VSA0DConsecutive(uint8_t* const bytes, uint32_t& runningChecksum, std::shared_ptr<VSA0DFirst> first, bool isLastRecord = false);
|
||||
|
||||
/**
|
||||
* Determine whether to filter out this message record. Utilizes the filter from the first record.
|
||||
*
|
||||
* @param filter The filter to check this record against
|
||||
*
|
||||
* @return True if this record passes the filter
|
||||
*/
|
||||
bool filter(const std::shared_ptr<VSAMessageReadFilter> filter) override { return first ? first->filter(filter) : false; }
|
||||
|
||||
/**
|
||||
* Get the timestamp of this record in 25 nanosecond ticks since January 1, 2007.
|
||||
*
|
||||
* @return Timestamp in 25 nanosecond ticks since January 1, 2007.
|
||||
*/
|
||||
uint64_t getTimestamp() override { return first ? first->getTimestamp() : UINT64_MAX; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Perform checksum on this record with the given bytestream
|
||||
*
|
||||
* @param bytes The bytestream to test the checksum against
|
||||
*/
|
||||
void doChecksum(uint8_t* bytes) override;
|
||||
|
||||
uint32_t recordChecksum; // The checksum for this extended record sequence found in the last record (not used if not last record)
|
||||
|
||||
uint32_t calculatedChecksum = 0; // Running checksum total for the extended record sequence of this record
|
||||
|
||||
std::shared_ptr<VSA0DFirst> first = nullptr; // The first record in this extended message record series
|
||||
};
|
||||
|
||||
} // namespace icsneo
|
||||
|
||||
#endif //__cplusplus
|
||||
#endif // __VSA0D_H__
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user