Author SHA1 Message Date
David RebbeandKyle Schwarz 06f6861130 Legacy: Drop deprecated APIs
Drop icsneoFindNeoDevices() and icsneoOpenNeoDevice() in favor of icsneoFindDevices() and icsneoOpenDevice(), respectively.

Also fixes:
- Failure to re-open a device after it has been closed with the C/legacy APIs
- NumberOfClients not being updated
- FIRE3 settings missing in icsneoGetDeviceSettingsType()
2024-03-07 19:45:46 +00:00
Jonathan Schwartz 219a5edbd8 Fixes Windows build with TCP enabled 2024-02-23 14:16:15 +00:00
Emily Brooks 05888e5c20 Device: Set multiple root directory entry flags at once 2024-02-14 18:06:59 -05:00
Bryant Jones e37d939699 Build: Fix warning on Comet2 missing override keyword 2024-02-14 15:37:09 +00:00
Bryant Jones 2a94b4566b RAD-A2B: Update settings structure 2024-02-14 10:04:14 -05:00
Kyle SchwarzandKyle Johannes 4782e26bed Device: Add isOnlineSupported() 2024-02-13 21:24:51 +00:00
Yasser Yassine 3264a1ecbe RAD-A2B: Fix RADA2BSettings::getChannelSize function 2024-01-23 23:18:01 +00:00
Yasser Yassine 1dfed4c9c4 A2B: Set timestamp field in HardwareA2BPacket::DecodeToMessage 2024-01-22 22:44:06 +00:00
Max Brombach a44952be13 Disk: Update VSA Example and Fix VSA CAN-FD Decode
- Send and validate CAN/CAN-FD/Eth frames in VSA example (two devices)
- Fix failure to decode CAN-FD frames from VSA records
2024-01-16 18:01:10 +00:00
Yasser Yassine 75e9319c32 A2B: Add example for reading/writing A2B board I2C registers 2024-01-12 20:34:11 +00:00
Bryant Jones 9df4aed19f Device: Add RAD-Comet2 support 2024-01-04 14:48:13 +00:00
Kyle Schwarz d56e66afd3 All: Bump copyright to 2024 2024-01-02 08:23:51 -05:00
jschwartz 26b52237e4 Communication: Increase device timeout in overloaded waitForMessageSync 2023-12-07 16:03:31 -05:00
Jonathan Schwartz 28ba94fa25 Remove RTTI dependency, increase default timeout for communication 2023-12-06 22:35:17 +00:00
Kyle Johannes e56c714a0c LIN: update example 2023-12-05 17:30:40 -05:00
Jonathan SchwartzandKyle Johannes 58f53edea8 Update device timeouts 2023-12-01 23:29:42 +00:00
Kyle Schwarz 3d2d3cb43d CI: Add Fedora 38 & 39 jobs 2023-12-01 22:39:46 +00:00
Kyle SchwarzandKyle Johannes bddbcfcf6d CI: Fix warnings 2023-12-01 22:20:41 +00:00
0497b361ef LIN: Settings API (#62)
* Settings: add APIs for LIN configuration

Add getter/setter for LIN configuration:
- baudrate
- commander resistor ON/OFF
- mode (SLEEP, SLOW, NORMAL, FAST)

* Device: add LIN settings getter for devices with LIN
* LIN: add setup to LIN example
* LIN: settings minor tweaks from PR

---------

Co-authored-by: Francesco Valla <francesco.valla@mta.it>
2023-11-30 15:56:18 -05:00
Max Brombach 02f1b4592e Device/Disk: Add VSA read and parse functionality
Implement ability to extract network traffic (CAN, LIN, Ethernet, etc.) from VSA message records on disk. Add a method to Device class that uses the VSAParser and the individual record types to extract messages from the VSA message records and pass them back to the communication system. This routes messages such that it appears as if they were discovered live instead of read from disk. The parse process (in Device) requires determination of metadata about the VSA file system on a device before it can begin extracting messages. This currently only handles data captured from the current coremini script on a device.
2023-11-15 16:02:47 +00:00
Yasser Yassine 4248c1a538 Device: Add CoreMini flashing support 2023-11-08 18:47:03 -05:00
Kyle Schwarz ec51393dfc CMake: Require Threads package 2023-11-06 17:39:11 -05:00
118 changed files with 6304 additions and 1930 deletions
+56
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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:
+19 -15
View File
@@ -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
return false;
}
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
+1 -1
View File
@@ -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
+34
View File
@@ -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 -2
View File
@@ -1,6 +1,5 @@
#include "icsneo/icsneocpp.h"
#include "icsneo/device/devicefinder.h"
#include <jni.h>
using namespace icsneo;
@@ -46,4 +45,4 @@ void icsneo::SetEventLimit(size_t newLimit) {
size_t icsneo::GetEventLimit() {
return EventManager::GetInstance().getEventLimit();
}
}
@@ -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
View File
@@ -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,107 +306,79 @@ 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
{
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)
// return the size only if devs is NULL.
if (!devs)
{
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;
}
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);
// 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()
);
}
catch (const std::out_of_range&)
{
return false;
}
*hObject = device;
if (!icsneo_openDevice(device))
return false;
// 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;
};
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
// 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 icsneoOpenDevice(
@@ -443,19 +403,50 @@ int LegacyDLLExport icsneoOpenDevice(
return false;
}
*hObject = device;
if(!icsneo_openDevice(device))
if (pNeoDeviceEx->neoDevice.NumberOfClients >= pNeoDeviceEx->neoDevice.MaxAllowedClients) {
return false;
}
*hObject = device;
if(!icsneo_openDevice(device)) {
return false;
}
return icsneo_setPollingMessageLimit(device, 20000) && icsneo_enableMessagePolling(device) && icsneo_goOnline(device);
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;
}
+1
View File
@@ -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: {
+6 -7
View File
@@ -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();
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
+1199 -48
View File
File diff suppressed because it is too large Load Diff
+18 -10
View File
@@ -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();
@@ -69,10 +77,6 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
#ifdef ICSNEO_ENABLE_CDCACM
CDCACM::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_ANDROIDUSB
ANDROIDUSB::Find(newDriverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_FTDI
@@ -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_
+235
View File
@@ -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);
+12 -8
View File
@@ -18,18 +18,20 @@ std::optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communicatio
const uint64_t currentSector = pos / SectorSize;
const uint8_t memLocation = (uint8_t)memType;
uint64_t numWords = amount / 2;
auto msg = com.waitForMessageSync([&currentSector, &memLocation, &com] {
auto msg = com.waitForMessageSync([&currentSector, &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([&currentSector, &memLocation, &com, from, amount] {
uint64_t numWords = amount / 2;
auto msg = com.waitForMessageSync([&currentSector, &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);
+43
View File
@@ -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;
}
}
+26
View File
@@ -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);
}
+24
View File
@@ -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);
}
+24
View File
@@ -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);
}
+23
View File
@@ -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);
}
+25
View File
@@ -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);
}
+25
View File
@@ -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);
}
+24
View File
@@ -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);
}
+32
View File
@@ -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);
}
+38
View File
@@ -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;
}
+27
View File
@@ -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);
}
+107
View File
@@ -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*>(&timestamp);
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);
}
+114
View File
@@ -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*>(&timestamp);
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);
}
+106
View File
@@ -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);
}
+37
View File
@@ -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);
}
+460
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
+5
View File
@@ -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()
-12
View File
@@ -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})
+3 -1
View File
@@ -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)) {
-3
View File
@@ -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)
+7 -8
View File
@@ -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 {
+6 -7
View File
@@ -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 {
-12
View File
@@ -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})
+3 -1
View File
@@ -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)) {
-25
View File
@@ -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)
+88 -2
View File
@@ -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;
}
-25
View File
@@ -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)
+18 -7
View File
@@ -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;
}
-25
View File
@@ -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)
-25
View File
@@ -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)
+63 -57
View File
@@ -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... ";
ret = device->goOffline();
std::cout << (ret ? "OK" : "FAIL") << std::endl;
std::cout << "\tDisconnecting... ";
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;
}
}
device->removeMessageCallback(handler);
std::cout << "Going offline... ";
ret = device->goOffline();
std::cout << (ret ? "OK" : "FAIL") << std::endl;
std::cout << "Disconnecting... ";
ret = device->close();
std::cout << (ret ? "OK\n" : "FAIL\n") << std::endl;
}
return 0;
}
-25
View File
@@ -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)
-25
View File
@@ -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)
-25
View File
@@ -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)
+2
View File
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-vsa-example src/VSAExample.cpp)
target_link_libraries(libicsneocpp-vsa-example icsneocpp)
+251
View File
@@ -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;
}
+727 -727
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -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
View File
@@ -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,
+2 -1
View File
@@ -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,
};
+4 -3
View File
@@ -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
+223 -3
View File
@@ -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,8 +589,20 @@ 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();
};
}
+62 -4
View File
@@ -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 {
+9 -47
View File
@@ -3,70 +3,32 @@
#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); }
};
}
#endif // __cplusplus
#endif
#endif
@@ -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);
+313
View File
@@ -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__
+55
View File
@@ -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__
+54
View File
@@ -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__
+49
View File
@@ -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__
+79
View File
@@ -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__
+49
View File
@@ -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__
+49
View File
@@ -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__
+46
View File
@@ -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__
+63
View File
@@ -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__
+57
View File
@@ -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__
+54
View File
@@ -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__

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