Merge branch 'v0.3.0-dev' into VUP-7

pull/49/head
Nguyen Trung Thanh 2022-04-27 01:29:00 +07:00 committed by GitHub
commit 0633bdbdaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
491 changed files with 64902 additions and 35023 deletions

51
.gitlab-ci.yml 100644
View File

@ -0,0 +1,51 @@
stages:
- build
- test
build windows/x64:
stage: build
script:
- CMD.EXE /C ci\build-windows64.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- icsneo-windows
test windows/x64:
stage: test
script:
- build\libicsneo-tests.exe
dependencies:
- build windows/x64
needs:
- build windows/x64
tags:
- icsneo-windows
timeout: 3m
build windows/x86:
stage: build
script:
- CMD.EXE /C ci\build-windows32.bat
artifacts:
when: always
paths:
- build
expire_in: 3 days
tags:
- icsneo-windows
test windows/x86:
stage: test
script:
- build\libicsneo-tests.exe
dependencies:
- build windows/x86
needs:
- build windows/x86
tags:
- icsneo-windows
timeout: 3m

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.2)
project(libicsneo VERSION 0.2.0) project(libicsneo VERSION 0.3.0)
option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF) option(LIBICSNEO_BUILD_TESTS "Build all tests." OFF)
option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF) option(LIBICSNEO_BUILD_DOCS "Build documentation. Don't use in Visual Studio." OFF)
@ -9,7 +9,18 @@ option(LIBICSNEO_BUILD_ICSNEOC_STATIC "Build static C library" ON)
option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON) option(LIBICSNEO_BUILD_ICSNEOLEGACY "Build icsnVC40 compatibility library" ON)
set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap") set(LIBICSNEO_NPCAP_INCLUDE_DIR "" CACHE STRING "Npcap include directory; set to build with Npcap")
set(CMAKE_CXX_STANDARD_REQUIRED 11) # Device Drivers
# You almost certainly don't want firmio for your build,
# it is only relevant for communication between Linux and
# CoreMini from the onboard processor of the device.
option(LIBICSNEO_ENABLE_FIRMIO "Enable communication between Linux and CoreMini within the same device" OFF)
option(LIBICSNEO_ENABLE_RAW_ETHERNET "Enable devices which communicate over raw ethernet" ON)
option(LIBICSNEO_ENABLE_CDCACM "Enable devices which communicate over USB CDC ACM" ON)
option(LIBICSNEO_ENABLE_FTDI "Enable devices which communicate over USB FTDI2XX" ON)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
endif()
include(GNUInstallDirs) include(GNUInstallDirs)
@ -84,17 +95,47 @@ endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(PLATFORM_SRC set(PLATFORM_SRC
platform/windows/pcap.cpp
platform/windows/registry.cpp platform/windows/registry.cpp
platform/windows/vcp.cpp )
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/windows/pcap.cpp
platform/windows/internal/pcapdll.cpp platform/windows/internal/pcapdll.cpp
) )
endif()
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/windows/vcp.cpp
)
endif()
else() # Darwin or Linux else() # Darwin or Linux
set(PLATFORM_SRC set(PLATFORM_SRC)
platform/posix/ftdi.cpp
if(LIBICSNEO_ENABLE_FIRMIO)
list(APPEND PLATFORM_SRC
platform/posix/firmio.cpp
)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/posix/pcap.cpp platform/posix/pcap.cpp
)
endif()
if(LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/posix/ftdi.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC
platform/posix/cdcacm.cpp platform/posix/cdcacm.cpp
) )
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
list(APPEND PLATFORM_SRC list(APPEND PLATFORM_SRC
platform/posix/darwin/cdcacmdarwin.cpp platform/posix/darwin/cdcacmdarwin.cpp
@ -105,12 +146,13 @@ else() # Darwin or Linux
) )
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
message(WARNING message(WARNING
"There is no platform port defined for ${CMAKE_SYSTEM_NAME}!\n" "There is no CDCACM platform port defined for ${CMAKE_SYSTEM_NAME}!\n"
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly." "The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly."
) )
endif() endif()
endif() endif()
endif() endif()
endif()
if(LIBICSNEO_BUILD_EXAMPLES) if(LIBICSNEO_BUILD_EXAMPLES)
add_subdirectory(examples) add_subdirectory(examples)
@ -127,11 +169,14 @@ endforeach()
set(SRC_FILES set(SRC_FILES
communication/message/flexray/control/flexraycontrolmessage.cpp communication/message/flexray/control/flexraycontrolmessage.cpp
communication/message/neomessage.cpp communication/message/neomessage.cpp
communication/message/ethphymessage.cpp
communication/packet/flexraypacket.cpp communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp communication/packet/canpacket.cpp
communication/packet/ethernetpacket.cpp communication/packet/ethernetpacket.cpp
communication/packet/versionpacket.cpp communication/packet/versionpacket.cpp
communication/packet/iso9141packet.cpp communication/packet/iso9141packet.cpp
communication/packet/ethphyregpacket.cpp
communication/packet/logicaldiskinfopacket.cpp
communication/decoder.cpp communication/decoder.cpp
communication/encoder.cpp communication/encoder.cpp
communication/ethernetpacketizer.cpp communication/ethernetpacketizer.cpp
@ -144,6 +189,14 @@ set(SRC_FILES
device/idevicesettings.cpp device/idevicesettings.cpp
device/devicefinder.cpp device/devicefinder.cpp
device/device.cpp device/device.cpp
device/neodevice.cpp
disk/diskreaddriver.cpp
disk/diskwritedriver.cpp
disk/nulldiskdriver.cpp
disk/neomemorydiskdriver.cpp
disk/plasiondiskreaddriver.cpp
disk/extextractordiskreaddriver.cpp
disk/fat.cpp
${PLATFORM_SRC} ${PLATFORM_SRC}
) )
@ -208,6 +261,22 @@ set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums) target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS}) message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS}) target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
if(LIBICSNEO_ENABLE_FIRMIO)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FIRMIO)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_RAW_ETHERNET)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
endif()
if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
endif()
# fatfs
add_subdirectory(third-party/fatfs)
target_link_libraries(icsneocpp PRIVATE fatfs)
# libftdi # libftdi
if(NOT WIN32) if(NOT WIN32)
@ -220,7 +289,7 @@ if(NOT WIN32)
set(FTDIPP OFF CACHE INTERNAL "") set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "") set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi) add_subdirectory(third-party/libftdi)
include_directories(${LIBUSB_INCLUDE_DIR}) target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
endif(NOT WIN32) endif(NOT WIN32)
# winpcap # winpcap
@ -289,6 +358,7 @@ if(NOT WIN32)
target_link_libraries(icsneocpp PUBLIC ftdi1-static) target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
find_package(PCAP REQUIRED) find_package(PCAP REQUIRED)
target_include_directories(icsneocpp PUBLIC ${PCAP_INCLUDE_DIR})
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY}) target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
endif() endif()
@ -298,22 +368,30 @@ if(LIBICSNEO_BUILD_TESTS)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif() endif()
if (NOT TARGET gtest)
add_subdirectory(third-party/googletest-master) add_subdirectory(third-party/googletest-master)
endif()
if (CMAKE_VERSION VERSION_LESS 2.8.11) if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include") include_directories("${gtest_SOURCE_DIR}/include")
endif() endif()
add_executable(runTests test/main.cpp test/eventmanagertest.cpp) add_executable(libicsneo-tests
test/main.cpp
test/diskdriverreadtest.cpp
test/diskdriverwritetest.cpp
test/eventmanagertest.cpp
test/ethernetpacketizertest.cpp
)
target_link_libraries(runTests gtest gtest_main) target_link_libraries(libicsneo-tests gtest gtest_main)
target_link_libraries(runTests icsneocpp) target_link_libraries(libicsneo-tests icsneocpp)
target_include_directories(runTests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) target_include_directories(libicsneo-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
enable_testing() enable_testing()
add_test(NAME testSuite COMMAND runTests) add_test(NAME libicsneo-test-suite COMMAND libicsneo-tests)
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})

View File

@ -453,7 +453,10 @@ bool icsneo_transmit(const neodevice_t* device, const neomessage_t* message) {
if(!icsneo_isValidNeoDevice(device)) if(!icsneo_isValidNeoDevice(device))
return false; return false;
return device->device->transmit(CreateMessageFromNeoMessage(message)); if(auto frame = std::dynamic_pointer_cast<icsneo::Frame>(CreateMessageFromNeoMessage(message)))
return device->device->transmit(frame);
return false;
} }
bool icsneo_transmitMessages(const neodevice_t* device, const neomessage_t* messages, size_t count) { bool icsneo_transmitMessages(const neodevice_t* device, const neomessage_t* messages, size_t count) {

View File

@ -70,6 +70,7 @@ static constexpr const char* DEVICE_NOT_CURRENTLY_POLLING = "The device is not c
static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network."; static constexpr const char* UNSUPPORTED_TX_NETWORK = "Message network is not a supported TX network.";
static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long."; static constexpr const char* MESSAGE_MAX_LENGTH_EXCEEDED = "The message was too long.";
static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present."; static constexpr const char* VALUE_NOT_YET_PRESENT = "The value is not yet present.";
static constexpr const char* TIMEOUT = "The timeout was reached.";
// Device Errors // Device Errors
static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!"; static constexpr const char* POLLING_MESSAGE_OVERFLOW = "Too many messages have been recieved for the polling message buffer, some have been lost!";
@ -102,6 +103,12 @@ static constexpr const char* ONLINE_NOT_SUPPORTED = "This device does not suppor
static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination."; static constexpr const char* TERMINATION_NOT_SUPPORTED_DEVICE = "This device does not support software selectable termination.";
static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device."; static constexpr const char* TERMINATION_NOT_SUPPORTED_NETWORK = "This network does not support software selectable termination on this device.";
static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled."; static constexpr const char* ANOTHER_IN_TERMINATION_GROUP_ENABLED = "A mutually exclusive network already has termination enabled.";
static constexpr const char* ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE = "Ethernet PHY register control is not available for this device.";
static constexpr const char* DISK_NOT_SUPPORTED = "This device does not support accessing the specified disk.";
static constexpr const char* EOF_REACHED = "The requested length exceeds the available data from this disk.";
static constexpr const char* SETTINGS_DEFAULTS_USED = "The device settings could not be loaded, the default settings have been applied.";
static constexpr const char* ATOMIC_OPERATION_RETRIED = "An operation failed to be atomically completed, but will be retried.";
static constexpr const char* ATOMIC_OPERATION_COMPLETED_NONATOMICALLY = "An ideally-atomic operation was completed nonatomically.";
// Transport Errors // Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed."; static constexpr const char* FAILED_TO_READ = "A read operation failed.";
@ -149,6 +156,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return MESSAGE_MAX_LENGTH_EXCEEDED; return MESSAGE_MAX_LENGTH_EXCEEDED;
case Type::ValueNotYetPresent: case Type::ValueNotYetPresent:
return VALUE_NOT_YET_PRESENT; return VALUE_NOT_YET_PRESENT;
case Type::Timeout:
return TIMEOUT;
// Device Errors // Device Errors
case Type::PollingMessageOverflow: case Type::PollingMessageOverflow:
@ -211,6 +220,18 @@ const char* APIEvent::DescriptionForType(Type type) {
return NO_SERIAL_NUMBER_12V; return NO_SERIAL_NUMBER_12V;
case Type::NoSerialNumberFW12V: case Type::NoSerialNumberFW12V:
return NO_SERIAL_NUMBER_FW_12V; return NO_SERIAL_NUMBER_FW_12V;
case Type::EthPhyRegisterControlNotAvailable:
return ETH_PHY_REGISTER_CONTROL_NOT_AVAILABLE;
case Type::DiskNotSupported:
return DISK_NOT_SUPPORTED;
case Type::EOFReached:
return EOF_REACHED;
case Type::SettingsDefaultsUsed:
return SETTINGS_DEFAULTS_USED;
case Type::AtomicOperationRetried:
return ATOMIC_OPERATION_RETRIED;
case Type::AtomicOperationCompletedNonatomically:
return ATOMIC_OPERATION_COMPLETED_NONATOMICALLY;
// Transport Errors // Transport Errors
case Type::FailedToRead: case Type::FailedToRead:

View File

@ -8,6 +8,99 @@ EventManager& EventManager::GetInstance() {
return inst; return inst;
} }
void EventManager::downgradeErrorsOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = true;
} else {
downgradedThreads.insert({std::this_thread::get_id(), true});
}
}
void EventManager::cancelErrorDowngradingOnCurrentThread() {
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = false;
}
}
void EventManager::add(APIEvent event) {
if(destructing)
return;
if(event.getSeverity() == APIEvent::Severity::Error) {
// if the error was added on a thread that downgrades errors (non-user thread)
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end() && i->second) {
event.downgradeFromError();
{
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
} else {
std::lock_guard<std::mutex> errorsLock(errorsMutex);
lastUserErrors[std::this_thread::get_id()] = event;
}
} else {
{
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
}
}
void EventManager::addEventInternal(APIEvent event) {
// Ensure the event list is at most exactly full (size of eventLimit - 1, leaving room for a potential APIEvent::TooManyEvents)
// Removes any events of type TooManyEvents from the end before checking to avoid duplicates.
enforceLimit();
// We are exactly full, either because the list was truncated or because we were simply full before
if(events.size() == eventLimit - 1) {
// If the event is worth adding
if(event.getType() != APIEvent::Type::TooManyEvents) {
discardOldest(1);
events.push_back(event);
}
events.push_back(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
} else {
if (event.getType() != APIEvent::Type::TooManyEvents)
events.push_back(event);
}
}
void EventManager::runCallbacks(APIEvent event) {
std::lock_guard<std::mutex> lk(callbacksMutex);
for(auto& i : callbacks)
i.second.callIfMatch(std::make_shared<APIEvent>(event));
}
void EventManager::setEventLimit(size_t newLimit) {
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
if(newLimit == eventLimit)
return;
if(newLimit < 10) {
add(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return;
}
eventLimit = newLimit;
std::lock_guard<std::mutex> eventsLock(eventsMutex);
if(enforceLimit())
addEventInternal(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
}
void EventManager::ResetInstance() { void EventManager::ResetInstance() {
std::lock_guard<std::mutex> eventsLock(eventsMutex); std::lock_guard<std::mutex> eventsLock(eventsMutex);
std::lock_guard<std::mutex> errorsLock(errorsMutex); std::lock_guard<std::mutex> errorsLock(errorsMutex);
@ -98,7 +191,7 @@ void EventManager::discard(EventFilter filter) {
}); });
} }
size_t EventManager::count_internal(EventFilter filter) const { size_t EventManager::countInternal(EventFilter filter) const {
size_t ret = 0; size_t ret = 0;
for(auto& event : events) for(auto& event : events)
if(filter.match(event)) if(filter.match(event))

View File

@ -27,8 +27,28 @@ using namespace icsneo;
typedef uint64_t legacymaphandle_t; typedef uint64_t legacymaphandle_t;
static std::map<legacymaphandle_t, neodevice_t> neodevices; static std::map<legacymaphandle_t, neodevice_t> neodevices;
static std::map<const size_t, size_t> mp_netIDToVnetOffSet = {{NETID_HSCAN, 1}, {NETID_MSCAN, 2}, {NETID_HSCAN2, 18}, {NETID_HSCAN3, 19}, {NETID_HSCAN4, 32}, {NETID_HSCAN5, 33}, {NETID_HSCAN6, 47}, {NETID_HSCAN7, 48}}; static const std::map<size_t, size_t> mp_netIDToVnetOffSet = {
static std::map<const size_t, size_t> mp_HWnetIDToCMnetID = {{NETID_HSCAN, 0}, {NETID_MSCAN, 1}, {NETID_HSCAN2, 5}, {NETID_HSCAN3, 8}, {NETID_HSCAN4, 14}, {NETID_HSCAN5, 15}, {NETID_HSCAN6, 32}, {NETID_HSCAN7, 33}}; {NETID_HSCAN, 1},
{NETID_MSCAN, 2},
{NETID_HSCAN2, 18},
{NETID_HSCAN3, 19},
{NETID_HSCAN4, 32},
{NETID_HSCAN5, 33},
{NETID_HSCAN6, 47},
{NETID_HSCAN7, 48},
};
static const std::map<size_t, size_t> mp_HWnetIDToCMnetID = {
{NETID_HSCAN, 0},
{NETID_MSCAN, 1},
{NETID_HSCAN2, 5},
{NETID_HSCAN3, 8},
{NETID_HSCAN4, 14},
{NETID_HSCAN5, 15},
{NETID_HSCAN6, 32},
{NETID_HSCAN7, 33},
};
static unsigned long vnet_table[] = {0, PLASMA_SLAVE1_OFFSET, PLASMA_SLAVE2_OFFSET}; static unsigned long vnet_table[] = {0, PLASMA_SLAVE1_OFFSET, PLASMA_SLAVE2_OFFSET};
static NeoDevice OldNeoDeviceFromNew(const neodevice_t* newnd) static NeoDevice OldNeoDeviceFromNew(const neodevice_t* newnd)
@ -38,40 +58,53 @@ static NeoDevice OldNeoDeviceFromNew(const neodevice_t *newnd)
oldnd.SerialNumber = icsneo_serialStringToNum(newnd->serial); oldnd.SerialNumber = icsneo_serialStringToNum(newnd->serial);
oldnd.NumberOfClients = 0; oldnd.NumberOfClients = 0;
oldnd.MaxAllowedClients = 1; oldnd.MaxAllowedClients = 1;
static_assert(sizeof(neodevice_handle_t) == sizeof(oldnd.Handle), "neodevice_handle_t size must be sizeof(int) for compatibility reasons"); static_assert(sizeof(neodevice_handle_t) == sizeof(oldnd.Handle),
"neodevice_handle_t size must be sizeof(int) for compatibility reasons");
oldnd.Handle = newnd->handle; oldnd.Handle = newnd->handle;
return oldnd; return oldnd;
} }
static void NeoMessageToSpyMessage(const neodevice_t *device, const neomessage_t &newmsg, icsSpyMessage &oldmsg) static bool NeoMessageToSpyMessage(const neodevice_t* device, const neomessage_t& newmsg, icsSpyMessage& oldmsg)
{ {
memset(&oldmsg, 0, sizeof(icsSpyMessage)); memset(&oldmsg, 0, sizeof(icsSpyMessage));
oldmsg.NumberBytesData = (uint8_t)std::min(newmsg.length, (size_t)255);
oldmsg.NumberBytesHeader = 4; // We currently only deal with frames
oldmsg.ExtraDataPtr = (void*)newmsg.data; if (newmsg.messageType != ICSNEO_MESSAGE_TYPE_FRAME)
oldmsg.ExtraDataPtrEnabled = newmsg.length > 8 ? 1 : 0; return false;
memcpy(oldmsg.Data, newmsg.data, std::min(newmsg.length, (size_t)8));
oldmsg.ArbIDOrHeader = *(uint32_t *)newmsg.header; const neomessage_frame_t& frame = *reinterpret_cast<const neomessage_frame_t*>(&newmsg);
oldmsg.NetworkID = (uint8_t)newmsg.netid; // Note: NetID remapping from the original API is not supported switch (Network::Type(frame.type))
oldmsg.DescriptionID = newmsg.description;
oldmsg.StatusBitField = newmsg.status.statusBitfield[0];
oldmsg.StatusBitField2 = newmsg.status.statusBitfield[1];
oldmsg.StatusBitField3 = newmsg.status.statusBitfield[2];
oldmsg.StatusBitField4 = newmsg.status.statusBitfield[3];
switch (Network::Type(newmsg.type))
{ {
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: case Network::Type::LSFTCAN:
oldmsg.Protocol = newmsg.status.canfdFDF ? SPY_PROTOCOL_CANFD : SPY_PROTOCOL_CAN; oldmsg.Protocol = frame.status.canfdFDF ? SPY_PROTOCOL_CANFD : SPY_PROTOCOL_CAN;
oldmsg.NumberBytesData = static_cast<uint8_t>(std::min(frame.length, (size_t)255));
oldmsg.NumberBytesHeader = 4;
break; break;
case Network::Type::Ethernet: case Network::Type::Ethernet:
oldmsg.Protocol = SPY_PROTOCOL_ETHERNET; oldmsg.Protocol = SPY_PROTOCOL_ETHERNET;
oldmsg.NumberBytesData = static_cast<uint8_t>(frame.length & 0xFF);
oldmsg.NumberBytesHeader = static_cast<uint8_t>(frame.length >> 8);
break; break;
default:
return false;
} }
oldmsg.ExtraDataPtr = (void*)frame.data;
oldmsg.ExtraDataPtrEnabled = frame.length > 8 ? 1 : 0;
memcpy(oldmsg.Data, frame.data, std::min(frame.length, (size_t)8));
oldmsg.ArbIDOrHeader = *reinterpret_cast<const uint32_t*>(frame.header);
oldmsg.NetworkID = static_cast<uint8_t>(frame.netid); // Note: NetID remapping from the original API is not supported
oldmsg.NetworkID2 = static_cast<uint8_t>(frame.netid >> 8);
oldmsg.DescriptionID = frame.description;
oldmsg.StatusBitField = frame.status.statusBitfield[0];
oldmsg.StatusBitField2 = frame.status.statusBitfield[1];
oldmsg.StatusBitField3 = frame.status.statusBitfield[2];
oldmsg.StatusBitField4 = frame.status.statusBitfield[3];
// Timestamp - epoch = 1/1/2007 - 25ns per tick most of the time // Timestamp - epoch = 1/1/2007 - 25ns per tick most of the time
uint64_t t = newmsg.timestamp; uint64_t t = frame.timestamp;
uint16_t res = 0; uint16_t res = 0;
if (icsneo_getTimestampResolution(device, &res)) if (icsneo_getTimestampResolution(device, &res))
{ {
@ -90,6 +123,8 @@ static void NeoMessageToSpyMessage(const neodevice_t *device, const neomessage_t
oldmsg.TimeStampHardwareID = HARDWARE_TIMESTAMP_ID_NONE; oldmsg.TimeStampHardwareID = HARDWARE_TIMESTAMP_ID_NONE;
} }
} }
return true;
} }
static inline bool Within(size_t value, size_t min, size_t max) static inline bool Within(size_t value, size_t min, size_t max)
@ -112,17 +147,25 @@ static inline bool IdIsSlaveBRange1(size_t fullNetid)
return Within(fullNetid, PLASMA_SLAVE2_OFFSET, PLASMA_SLAVE2_OFFSET + PLASMA_SLAVE_NUM); return Within(fullNetid, PLASMA_SLAVE2_OFFSET, PLASMA_SLAVE2_OFFSET + PLASMA_SLAVE_NUM);
} }
static inline bool IdIsSlaveBRange2(unsigned int fullNetid) static inline bool IdIsSlaveBRange2(size_t fullNetid)
{ {
return Within(fullNetid, PLASMA_SLAVE2_OFFSET_RANGE2, PLASMA_SLAVE3_OFFSET_RANGE2); return Within(fullNetid, PLASMA_SLAVE2_OFFSET_RANGE2, PLASMA_SLAVE3_OFFSET_RANGE2);
} }
static inline unsigned int GetVnetNetid(size_t simpleNetId, EPlasmaIonVnetChannel_t vnetSlot) static inline bool GetVnetNetid(size_t& netId, EPlasmaIonVnetChannel_t vnetSlot)
{ {
if (vnetSlot == 0 || vnetSlot > 3) if (vnetSlot == 0)
return simpleNetId; return true;
return mp_netIDToVnetOffSet[simpleNetId] + vnet_table[vnetSlot]; if (vnetSlot >= sizeof(vnet_table)/sizeof(vnet_table[0]))
return false;
const auto offset = mp_netIDToVnetOffSet.find(netId);
if (offset == mp_netIDToVnetOffSet.end())
return false;
netId = offset->second + vnet_table[vnetSlot];
return true;
} }
/** /**
@ -130,7 +173,7 @@ static inline unsigned int GetVnetNetid(size_t simpleNetId, EPlasmaIonVnetChanne
* the offset from PLASMA_SLAVE1_OFFSET2, return the vnet agnostic * the offset from PLASMA_SLAVE1_OFFSET2, return the vnet agnostic
* netid so caller can commonize handlers without caring about WHICH slave. * netid so caller can commonize handlers without caring about WHICH slave.
*/ */
static inline unsigned int OffsetToSimpleNetworkId(size_t offset) static inline size_t OffsetToSimpleNetworkId(size_t offset)
{ {
for (const auto& it : mp_netIDToVnetOffSet) for (const auto& it : mp_netIDToVnetOffSet)
{ {
@ -140,31 +183,22 @@ static inline unsigned int OffsetToSimpleNetworkId(size_t offset)
return NETID_DEVICE; return NETID_DEVICE;
} }
static inline unsigned int GetVnetAgnosticNetid(size_t fullNetid) static inline size_t GetVnetAgnosticNetid(size_t fullNetid)
{ {
if (IdIsSlaveARange1(fullNetid)) if (IdIsSlaveARange1(fullNetid))
{ return OffsetToSimpleNetworkId(fullNetid - PLASMA_SLAVE1_OFFSET);
unsigned int off = fullNetid - PLASMA_SLAVE1_OFFSET;
return OffsetToSimpleNetworkId(off);
}
else if (IdIsSlaveARange2(fullNetid)) else if (IdIsSlaveARange2(fullNetid))
{
return fullNetid - PLASMA_SLAVE1_OFFSET_RANGE2; return fullNetid - PLASMA_SLAVE1_OFFSET_RANGE2;
}
else if (IdIsSlaveBRange1(fullNetid)) else if (IdIsSlaveBRange1(fullNetid))
{ return OffsetToSimpleNetworkId(fullNetid - PLASMA_SLAVE2_OFFSET);
unsigned int off = fullNetid - PLASMA_SLAVE2_OFFSET;
return OffsetToSimpleNetworkId(off);
}
else if (IdIsSlaveBRange2(fullNetid)) else if (IdIsSlaveBRange2(fullNetid))
{
return fullNetid - PLASMA_SLAVE2_OFFSET_RANGE2; return fullNetid - PLASMA_SLAVE2_OFFSET_RANGE2;
}
return fullNetid; return fullNetid;
} }
//Basic Functions //Basic Functions
int LegacyDLLExport icsneoFindDevices(NeoDeviceEx *devs, int *devCount, unsigned int *devTypes, unsigned int devTypeCount, POptionsFindNeoEx *POptionsFindNeoEx, unsigned int *zero) int LegacyDLLExport icsneoFindDevices(NeoDeviceEx* devs, int* devCount, unsigned int* devTypes, unsigned int devTypeCount,
POptionsFindNeoEx* POptionsFindNeoEx, unsigned int* zero)
{ {
if (!devs || !devCount) if (!devs || !devCount)
return 0; return 0;
@ -194,7 +228,7 @@ int LegacyDLLExport icsneoFindDevices(NeoDeviceEx *devs, int *devCount, unsigned
if (devTypes && devTypeCount) if (devTypes && devTypeCount)
{ {
for (auto j = 0; j < devTypeCount; j++) for (unsigned int j = 0; j < devTypeCount; j++)
{ {
if (foundDevices[i].DeviceType == devTypes[j]) if (foundDevices[i].DeviceType == devTypes[j])
{ {
@ -302,7 +336,7 @@ int LegacyDLLExport icsneoClosePort(void *hObject, int *pNumberOfErrors)
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return icsneo_closeDevice(device); return icsneo_closeDevice(device);
} }
@ -326,17 +360,20 @@ int LegacyDLLExport icsneoGetMessages(void *hObject, icsSpyMessage *pMsg, int *p
static neomessage_t messages[20000]; static neomessage_t messages[20000];
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
size_t messageCount = 20000; size_t messageCount = 20000;
if (!icsneo_getMessages(device, messages, &messageCount, 0)) if (!icsneo_getMessages(device, messages, &messageCount, 0))
return false; return false;
*pNumberOfMessages = (int)messageCount; *pNumberOfMessages = 0;
*pNumberOfErrors = 0; *pNumberOfErrors = 0;
for (size_t i = 0; i < messageCount; i++) for (size_t i = 0; i < messageCount; i++)
NeoMessageToSpyMessage(device, messages[i], pMsg[i]); {
if (NeoMessageToSpyMessage(device, messages[i], pMsg[*pNumberOfMessages]))
(*pNumberOfMessages)++;
}
return true; return true;
} }
@ -346,12 +383,13 @@ int LegacyDLLExport icsneoTxMessages(void *hObject, icsSpyMessage *pMsg, int lNe
return icsneoTxMessagesEx(hObject, pMsg, lNetworkID, lNumMessages, nullptr, 0); return icsneoTxMessagesEx(hObject, pMsg, lNetworkID, lNumMessages, nullptr, 0);
} }
int LegacyDLLExport icsneoTxMessagesEx(void *hObject, icsSpyMessage *pMsg, unsigned int lNetworkID, unsigned int lNumMessages, unsigned int *NumTxed, unsigned int zero2) int LegacyDLLExport icsneoTxMessagesEx(void* hObject, icsSpyMessage* pMsg, unsigned int lNetworkID, unsigned int lNumMessages,
unsigned int* NumTxed, unsigned int zero2)
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
neomessage_t newmsg; neomessage_frame_t newmsg;
unsigned int temp = 0; unsigned int temp = 0;
if (NumTxed == nullptr) if (NumTxed == nullptr)
NumTxed = &temp; NumTxed = &temp;
@ -377,7 +415,7 @@ int LegacyDLLExport icsneoTxMessagesEx(void *hObject, icsSpyMessage *pMsg, unsig
newmsg.status.statusBitfield[3] = oldmsg.StatusBitField4; newmsg.status.statusBitfield[3] = oldmsg.StatusBitField4;
if (oldmsg.Protocol == SPY_PROTOCOL_CANFD) if (oldmsg.Protocol == SPY_PROTOCOL_CANFD)
newmsg.status.canfdFDF = true; newmsg.status.canfdFDF = true;
if (icsneo_transmit(device, &newmsg)) if (icsneo_transmit(device, reinterpret_cast<neomessage_t*>(&newmsg)))
(*NumTxed)++; (*NumTxed)++;
} }
return lNumMessages == *NumTxed; return lNumMessages == *NumTxed;
@ -392,7 +430,7 @@ int LegacyDLLExport icsneoEnableNetworkRXQueue(void *hObject, int iEnable)
int LegacyDLLExport icsneoGetTimeStampForMsg(void* hObject, icsSpyMessage* pMsg, double* pTimeStamp) { int LegacyDLLExport icsneoGetTimeStampForMsg(void* hObject, icsSpyMessage* pMsg, double* pTimeStamp) {
if(!icsneoValidateHObject(hObject)) if(!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
uint16_t resolution = 0; uint16_t resolution = 0;
if (!icsneo_getTimestampResolution(device, &resolution)) if (!icsneo_getTimestampResolution(device, &resolution))
@ -412,14 +450,15 @@ int LegacyDLLExport icsneoGetTimeStampForMsg(void* hObject, icsSpyMessage* pMsg,
return true; return true;
} }
void LegacyDLLExport icsneoGetISO15765Status(void *hObject, int lNetwork, int lClearTxStatus, int lClearRxStatus, int *lTxStatus, int *lRxStatus) void LegacyDLLExport icsneoGetISO15765Status(void* hObject, int lNetwork, int lClearTxStatus, int lClearRxStatus,
int* lTxStatus, int* lRxStatus)
{ {
// TODO Implement // TODO Implement
return; return;
} }
void LegacyDLLExport icsneoSetISO15765RxParameters(void *hObject, int lNetwork, int lEnable, spyFilterLong *pFF_CFMsgFilter, icsSpyMessage *pTxMsg, void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork, int lEnable, spyFilterLong* pFF_CFMsgFilter,
int lCFTimeOutMs, int lFlowCBlockSize, int lUsesExtendedAddressing, int lUseHardwareIfPresent) icsSpyMessage* pTxMsg, int lCFTimeOutMs, int lFlowCBlockSize, int lUsesExtendedAddressing, int lUseHardwareIfPresent)
{ {
// TODO Implement // TODO Implement
return; return;
@ -442,7 +481,7 @@ int LegacyDLLExport icsneoGetFireSettings(void *hObject, SFireSettings *pSetting
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -450,7 +489,7 @@ int LegacyDLLExport icsneoSetFireSettings(void *hObject, SFireSettings *pSetting
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -460,7 +499,7 @@ int LegacyDLLExport icsneoGetVCAN3Settings(void *hObject, SVCAN3Settings *pSetti
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -468,7 +507,7 @@ int LegacyDLLExport icsneoSetVCAN3Settings(void *hObject, SVCAN3Settings *pSetti
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -478,7 +517,7 @@ int LegacyDLLExport icsneoGetFire2Settings(void *hObject, SFire2Settings *pSetti
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -486,7 +525,7 @@ int LegacyDLLExport icsneoSetFire2Settings(void *hObject, SFire2Settings *pSetti
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -496,7 +535,7 @@ int LegacyDLLExport icsneoGetVCANRFSettings(void *hObject, SVCANRFSettings *pSet
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -504,7 +543,7 @@ int LegacyDLLExport icsneoSetVCANRFSettings(void *hObject, SVCANRFSettings *pSet
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -514,7 +553,7 @@ int LegacyDLLExport icsneoGetVCAN412Settings(void *hObject, SVCAN412Settings *pS
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -522,7 +561,7 @@ int LegacyDLLExport icsneoSetVCAN412Settings(void *hObject, SVCAN412Settings *pS
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -532,7 +571,7 @@ int LegacyDLLExport icsneoGetRADGalaxySettings(void *hObject, SRADGalaxySettings
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -540,7 +579,7 @@ int LegacyDLLExport icsneoSetRADGalaxySettings(void *hObject, SRADGalaxySettings
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -550,7 +589,7 @@ int LegacyDLLExport icsneoGetRADStar2Settings(void *hObject, SRADStar2Settings *
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1); return !!(icsneo_settingsReadStructure(device, pSettings, iNumBytes) + 1);
} }
@ -558,7 +597,7 @@ int LegacyDLLExport icsneoSetRADStar2Settings(void *hObject, SRADStar2Settings *
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -568,22 +607,24 @@ int LegacyDLLExport icsneoSetBitRate(void *hObject, int BitRate, int NetworkID)
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (!icsneo_setBaudrate(device, (uint16_t)NetworkID, BitRate)) if (!icsneo_setBaudrate(device, (uint16_t)NetworkID, BitRate))
return false; return false;
return icsneo_settingsApply(device); return icsneo_settingsApply(device);
} }
int LegacyDLLExport icsneoSetFDBitRate(void* hObject, int BitRate, int NetworkID) { int LegacyDLLExport icsneoSetFDBitRate(void* hObject, int BitRate, int NetworkID)
{
if(!icsneoValidateHObject(hObject)) if(!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if(!icsneo_setFDBaudrate(device, (uint16_t)NetworkID, BitRate)) if(!icsneo_setFDBaudrate(device, (uint16_t)NetworkID, BitRate))
return false; return false;
return icsneo_settingsApply(device); return icsneo_settingsApply(device);
} }
int LegacyDLLExport icsneoGetDeviceParameters(void* hObject, char* pParameter, char* pValues, short ValuesLength) { int LegacyDLLExport icsneoGetDeviceParameters(void* hObject, char* pParameter, char* pValues, short ValuesLength)
{
// TODO Implement // TODO Implement
return false; return false;
} }
@ -607,7 +648,8 @@ int LegacyDLLExport icsneoGetErrorMessages(void *hObject, int *pErrorMsgs, int *
return false; return false;
} }
int LegacyDLLExport icsneoGetErrorInfo(int lErrorNumber, TCHAR *szErrorDescriptionShort, TCHAR *szErrorDescriptionLong, int *lMaxLengthShort, int *lMaxLengthLong, int *lErrorSeverity, int *lRestartNeeded) int LegacyDLLExport icsneoGetErrorInfo(int lErrorNumber, TCHAR* szErrorDescriptionShort, TCHAR* szErrorDescriptionLong,
int* lMaxLengthShort, int* lMaxLengthLong, int* lErrorSeverity, int* lRestartNeeded)
{ {
// TODO Implement // TODO Implement
return false; return false;
@ -626,7 +668,8 @@ int LegacyDLLExport icsneoISO15765_DisableNetworks(void *hObject)
return false; return false;
} }
int LegacyDLLExport icsneoISO15765_TransmitMessage(void *hObject, unsigned long ulNetworkID, stCM_ISO157652_TxMessage *pMsg, unsigned long ulBlockingTimeout) int LegacyDLLExport icsneoISO15765_TransmitMessage(void* hObject, unsigned long ulNetworkID, stCM_ISO157652_TxMessage* pMsg,
unsigned long ulBlockingTimeout)
{ {
// TODO Implement // TODO Implement
return false; return false;
@ -645,7 +688,7 @@ int LegacyDLLExport icsneoValidateHObject(void *hObject)
{ {
if (&it->second == hObject) if (&it->second == hObject)
{ {
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (icsneo_isValidNeoDevice(device)) if (icsneo_isValidNeoDevice(device))
return true; return true;
} }
@ -663,7 +706,7 @@ int LegacyDLLExport icsneoGetSerialNumber(void *hObject, unsigned int *iSerialNu
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
*iSerialNumber = icsneo_serialStringToNum(device->serial); *iSerialNumber = icsneo_serialStringToNum(device->serial);
return true; return true;
} }
@ -672,7 +715,7 @@ int LegacyDLLExport icsneoEnableDOIPLine(void* hObject, bool enable)
{ {
if(!icsneoValidateHObject(hObject)) if(!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return icsneo_setDigitalIO(device, ICSNEO_IO_ETH_ACTIVATION, 1, enable); return icsneo_setDigitalIO(device, ICSNEO_IO_ETH_ACTIVATION, 1, enable);
} }
@ -750,13 +793,15 @@ int LegacyDLLExport icsneoScriptWriteAppSignal(void *hObject, unsigned int iInde
} }
//Deprecated (but still suppored in the DLL) //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) int LegacyDLLExport icsneoOpenPortEx(void* lPortNumber, int lPortType, int lDriverType, int lIPAddressMSB,
int lIPAddressLSBOrBaudRate, int bConfigRead, unsigned char* bNetworkID, int* hObject)
{ {
// TODO Implement // TODO Implement
return false; return false;
} }
int LegacyDLLExport icsneoOpenPort(int lPortNumber, int lPortType, int lDriverType, unsigned char *bNetworkID, unsigned char *bSCPIDs, int *hObject) int LegacyDLLExport icsneoOpenPort(int lPortNumber, int lPortType, int lDriverType, unsigned char *bNetworkID,
unsigned char* bSCPIDs, int* hObject)
{ {
// TODO Implement // TODO Implement
return false; return false;
@ -766,7 +811,7 @@ int LegacyDLLExport icsneoEnableNetworkCom(void *hObject, int Enable)
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (Enable) if (Enable)
return icsneo_goOnline(device); return icsneo_goOnline(device);
@ -774,13 +819,15 @@ int LegacyDLLExport icsneoEnableNetworkCom(void *hObject, int Enable)
return icsneo_goOffline(device); 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) int LegacyDLLExport icsneoFindAllCOMDevices(int lDriverType, int lGetSerialNumbers, int lStopAtFirst, int lUSBCommOnly,
int* p_lDeviceTypes, int* p_lComPorts, int* p_lSerialNumbers, int* lNumDevices)
{ {
// TODO Implement // TODO Implement
return false; return false;
} }
int LegacyDLLExport icsneoOpenNeoDeviceByChannels(NeoDevice *pNeoDevice, void **hObject, unsigned char *uChannels, int iSize, int bConfigRead, int iOptions) int LegacyDLLExport icsneoOpenNeoDeviceByChannels(NeoDevice* pNeoDevice, void** hObject, unsigned char* uChannels, int iSize,
int bConfigRead, int iOptions)
{ {
// TODO Implement // TODO Implement
return false; return false;
@ -790,7 +837,7 @@ int LegacyDLLExport icsneoGetVCAN4Settings(void *hObject, SVCAN4Settings *pSetti
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes); return !!icsneo_settingsReadStructure(device, pSettings, iNumBytes);
} }
@ -798,7 +845,7 @@ int LegacyDLLExport icsneoSetVCAN4Settings(void *hObject, SVCAN4Settings *pSetti
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (bSaveToEEPROM) if (bSaveToEEPROM)
return icsneo_settingsApplyStructure(device, pSettings, iNumBytes); return icsneo_settingsApplyStructure(device, pSettings, iNumBytes);
return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes); return icsneo_settingsApplyStructureTemporary(device, pSettings, iNumBytes);
@ -809,7 +856,7 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void *hObject, EPlasmaIonVnetCha
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
unsigned long ulDeviceType = device->type; unsigned long ulDeviceType = device->type;
@ -870,12 +917,13 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void *hObject, EPlasmaIonVnetCha
return 1; return 1;
} }
int LegacyDLLExport icsneoSetDeviceSettings(void* hObject, SDeviceSettings* pSettings, int iNumBytes, int bSaveToEEPROM, EPlasmaIonVnetChannel_t vnetSlot) int LegacyDLLExport icsneoSetDeviceSettings(void* hObject, SDeviceSettings* pSettings, int iNumBytes, int bSaveToEEPROM,
EPlasmaIonVnetChannel_t vnetSlot)
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
const size_t offset = size_t(&pSettings->Settings) - size_t(pSettings); const size_t offset = size_t(&pSettings->Settings) - size_t(pSettings);
@ -890,7 +938,7 @@ int LegacyDLLExport icsneoGetDeviceSettings(void* hObject, SDeviceSettings* pSet
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (icsneoGetDeviceSettingsType(hObject, vnetSlot, &pSettings->DeviceSettingType) == 0) if (icsneoGetDeviceSettingsType(hObject, vnetSlot, &pSettings->DeviceSettingType) == 0)
return false; return false;
@ -903,7 +951,7 @@ int LegacyDLLExport icsneoSetBitRateEx(void *hObject, unsigned long BitRate, int
{ {
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
if (!icsneo_setBaudrate(device, (uint16_t)NetworkID, BitRate)) if (!icsneo_setBaudrate(device, (uint16_t)NetworkID, BitRate))
return false; return false;
@ -1041,12 +1089,13 @@ int LegacyDLLExport icsneoGetDLLFirmwareInfoEx(void *hObject, stAPIFirmwareInfo
int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short Len, void* pVoid) int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short Len, void* pVoid)
{ {
uint64_t* pTmp = nullptr; uint64_t* pTmp = nullptr;
int iRetVal = 0, iNumBytes = 0, NetworkID; int iRetVal = 0, iNumBytes = 0;
uint16_t NetworkID = 0;
if (!icsneoValidateHObject(hObject)) if (!icsneoValidateHObject(hObject))
return false; return false;
neodevice_t *device = (neodevice_t *)hObject; neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
switch (*CmdBuf) switch (*CmdBuf)
{ {
@ -1107,10 +1156,25 @@ int LegacyDLLExport icsneoJ2534Cmd(void *hObject, unsigned char *CmdBuf, short L
case NEODEVICE_ION: //FIRE2 VNETS case NEODEVICE_ION: //FIRE2 VNETS
SFire2Settings Cs; SFire2Settings Cs;
iNumBytes = sizeof(Cs); iNumBytes = sizeof(Cs);
if (!!icsneoGetFire2Settings(hObject, &Cs, iNumBytes)) if (icsneoGetFire2Settings(hObject, &Cs, iNumBytes))
(Cs.termination_enables & (1ull << mp_HWnetIDToCMnetID[GetVnetAgnosticNetid(NetworkID)])) ? *pTmp = 3 /*Termination ON*/ : *pTmp = 0 /*Termination OFF*/; {
const auto cmId = mp_HWnetIDToCMnetID.find(GetVnetAgnosticNetid(NetworkID));
if (cmId != mp_HWnetIDToCMnetID.end())
{
if (Cs.termination_enables & (1ull << cmId->second))
*pTmp = 3; // Termination ON
else else
*pTmp = 0; // Termination OFF
}
else
{
iRetVal = 0; iRetVal = 0;
}
}
else
{
iRetVal = 0;
}
break; break;
} }
break; break;
@ -1130,15 +1194,25 @@ int LegacyDLLExport icsneoJ2534Cmd(void *hObject, unsigned char *CmdBuf, short L
iNumBytes = sizeof(Cs); iNumBytes = sizeof(Cs);
if (icsneoGetFire2Settings(hObject, &Cs, iNumBytes)) if (icsneoGetFire2Settings(hObject, &Cs, iNumBytes))
{ {
unsigned long long CoremininetID = mp_HWnetIDToCMnetID[GetVnetAgnosticNetid(NetworkID)]; const auto cmId = mp_HWnetIDToCMnetID.find(GetVnetAgnosticNetid(NetworkID));
if (cmId != mp_HWnetIDToCMnetID.end())
{
if (*pTmp == 3) /*Termination ON*/ if (*pTmp == 3) /*Termination ON*/
Cs.termination_enables |= (1ull << CoremininetID); Cs.termination_enables |= (1ull << cmId->second);
else /*Termination OFF*/ else /*Termination OFF*/
Cs.termination_enables &= ~(1ull << CoremininetID); Cs.termination_enables &= ~(1ull << cmId->second);
iRetVal = icsneoSetFire2Settings(hObject, &Cs, iNumBytes, 1 /* ConfigurationOptionDoNotSaveToEEPROM */); iRetVal = icsneoSetFire2Settings(hObject, &Cs, iNumBytes, 1 /* ConfigurationOptionDoNotSaveToEEPROM */);
} }
else
{
iRetVal = 0;
}
}
else
{
iRetVal = 0;
}
break; break;
} }
break; break;
@ -1172,11 +1246,8 @@ int LegacyDLLExport icsneoGetBusVoltage(void *hObject, unsigned long *pVBusVolta
return false; return false;
} }
int LegacyDLLExport icsneoOpenRemoteNeoDevice(const char *pIPAddress, int LegacyDLLExport icsneoOpenRemoteNeoDevice(const char* pIPAddress, NeoDevice* pNeoDevice, void** hObject,
NeoDevice *pNeoDevice, unsigned char* bNetworkIDs, int iOptions)
void **hObject,
unsigned char *bNetworkIDs,
int iOptions)
{ {
return false; return false;
} }
@ -1203,7 +1274,8 @@ int LegacyDLLExport icsneoGetNetidforSlaveVNETs(size_t *NetworkIndex, EPlasmaIon
int LegacyDLLExport icsneoGetVnetSimpleNetid(size_t* FullNetID) int LegacyDLLExport icsneoGetVnetSimpleNetid(size_t* FullNetID)
{ {
return GetVnetAgnosticNetid(*FullNetID); *FullNetID = GetVnetAgnosticNetid(*FullNetID);
return true;
} }
int LegacyDLLExport icsneoSerialNumberFromString(unsigned long* serial, char* data) int LegacyDLLExport icsneoSerialNumberFromString(unsigned long* serial, char* data)

View File

@ -24,5 +24,5 @@ int LegacyDLLExport icsneoWaitForRxMessagesWithTimeOut(void* hObject, unsigned i
neodevice_t* device = (neodevice_t*)hObject; neodevice_t* device = (neodevice_t*)hObject;
if(device->device->getCurrentMessageCount() != 0) if(device->device->getCurrentMessageCount() != 0)
return true; return true;
return bool(device->device->com->waitForMessageSync(MessageFilter(), std::chrono::milliseconds(iTimeOut))); return bool(device->device->com->waitForMessageSync({}, std::chrono::milliseconds(iTimeOut)));
} }

View File

@ -0,0 +1,12 @@
REM clean intermediate directories
rmdir /s /q build
mkdir build
REM build
cd build
set CFLAGS=/WX
set CXXFLAGS=/WX
cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLIBICSNEO_BUILD_TESTS=ON ..
if %errorlevel% neq 0 exit /b %errorlevel%
cmake --build .
if %errorlevel% neq 0 exit /b %errorlevel%

View File

@ -0,0 +1,2 @@
call "%VCVARS32%"
call "ci\build-windows.bat"

View File

@ -0,0 +1,2 @@
call "%VCVARS64%"
call "ci\build-windows.bat"

View File

@ -79,6 +79,21 @@ bool Communication::sendCommand(Command cmd, std::vector<uint8_t> arguments) {
return sendPacket(packet); return sendPacket(packet);
} }
bool Communication::sendCommand(ExtendedCommand cmd, std::vector<uint8_t> arguments) {
const auto size = arguments.size();
if (size > std::numeric_limits<uint16_t>::max())
return false;
arguments.insert(arguments.begin(), {
uint8_t(uint16_t(cmd) & 0xff),
uint8_t((uint16_t(cmd) >> 8) & 0xff),
uint8_t(size & 0xff),
uint8_t((size >> 8) & 0xff)
});
return sendCommand(Command::Extended, arguments);
}
bool Communication::redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo) { bool Communication::redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo) {
if(redirectingRead) if(redirectingRead)
return false; return false;
@ -97,9 +112,10 @@ void Communication::clearRedirectRead() {
} }
bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) { bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::ReadSettings);
std::shared_ptr<Message> msg = waitForMessageSync([this]() { std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ }); return sendCommand(Command::ReadSettings, { 0, 0, 0, 1 /* Get Global Settings */, 0, 1 /* Subversion 1 */ });
}, MessageFilter(Network::NetID::ReadSettings), timeout); }, filter, timeout);
if(!msg) if(!msg)
return false; return false;
@ -109,35 +125,38 @@ bool Communication::getSettingsSync(std::vector<uint8_t>& data, std::chrono::mil
return false; return false;
} }
if(gsmsg->response != ReadSettingsMessage::Response::OK) { if(gsmsg->response == ReadSettingsMessage::Response::OKDefaultsUsed) {
report(APIEvent::Type::Unknown, APIEvent::Severity::Error); report(APIEvent::Type::SettingsDefaultsUsed, APIEvent::Severity::EventInfo);
} else if(gsmsg->response != ReadSettingsMessage::Response::OK) {
report(APIEvent::Type::SettingsReadError, APIEvent::Severity::Error);
return false; return false;
} }
data = std::move(msg->data); data = std::move(gsmsg->data);
return true; return true;
} }
std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) { std::shared_ptr<SerialNumberMessage> Communication::getSerialNumberSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<Main51MessageFilter>(Command::RequestSerialNumber);
std::shared_ptr<Message> msg = waitForMessageSync([this]() { std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::RequestSerialNumber); return sendCommand(Command::RequestSerialNumber);
}, Main51MessageFilter(Command::RequestSerialNumber), timeout); }, filter, timeout);
if(!msg) // Did not receive a message if(!msg) // Did not receive a message
return std::shared_ptr<SerialNumberMessage>(); return std::shared_ptr<SerialNumberMessage>();
auto m51 = std::dynamic_pointer_cast<Main51Message>(msg); auto m51 = std::dynamic_pointer_cast<Main51Message>(msg);
if(!m51) // Could not upcast for some reason if(!m51) // Could not upcast for some reason
return std::shared_ptr<SerialNumberMessage>(); return std::shared_ptr<SerialNumberMessage>();
return std::dynamic_pointer_cast<SerialNumberMessage>(m51); return std::dynamic_pointer_cast<SerialNumberMessage>(m51);
} }
optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersionsSync(std::chrono::milliseconds timeout) { optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersionsSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::DeviceVersion);
std::vector< optional<DeviceAppVersion> > ret; std::vector< optional<DeviceAppVersion> > ret;
std::shared_ptr<Message> msg = waitForMessageSync([this]() { std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::GetMainVersion); return sendCommand(Command::GetMainVersion);
}, Main51MessageFilter(Command::GetMainVersion), timeout); }, filter, timeout);
if(!msg) // Did not receive a message if(!msg) // Did not receive a message
return nullopt; return nullopt;
@ -145,24 +164,35 @@ optional< std::vector< optional<DeviceAppVersion> > > Communication::getVersions
if(!ver) // Could not upcast for some reason if(!ver) // Could not upcast for some reason
return nullopt; return nullopt;
if(!ver->MainChip || ver->Versions.size() != 1) if(ver->ForChip != VersionMessage::MainChip || ver->Versions.size() != 1)
return nullopt; return nullopt;
ret.push_back(ver->Versions.front()); ret.push_back(ver->Versions.front());
msg = waitForMessageSync([this]() { msg = waitForMessageSync([this]() {
return sendCommand(Command::GetSecondaryVersions); return sendCommand(Command::GetSecondaryVersions);
}, Main51MessageFilter(Command::GetSecondaryVersions), timeout); }, filter, timeout);
if(msg) { // This one is allowed to fail if(msg) { // This one is allowed to fail
ver = std::dynamic_pointer_cast<VersionMessage>(msg); ver = std::dynamic_pointer_cast<VersionMessage>(msg);
if(ver && !ver->MainChip) { if(ver && ver->ForChip != VersionMessage::MainChip)
ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end()); ret.insert(ret.end(), ver->Versions.begin(), ver->Versions.end());
} }
}
return ret; return ret;
} }
std::shared_ptr<LogicalDiskInfoMessage> Communication::getLogicalDiskInfoSync(std::chrono::milliseconds timeout) {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::LogicalDiskInfo);
std::shared_ptr<Message> msg = waitForMessageSync([this]() {
return sendCommand(Command::GetLogicalDiskInfo);
}, filter, timeout);
if(!msg) // Did not receive a message
return {};
return std::dynamic_pointer_cast<LogicalDiskInfoMessage>(msg);
}
int Communication::addMessageCallback(const MessageCallback& cb) { int Communication::addMessageCallback(const MessageCallback& cb) {
std::lock_guard<std::mutex> lk(messageCallbacksLock); std::lock_guard<std::mutex> lk(messageCallbacksLock);
messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb)); messageCallbacks.insert(std::make_pair(messageCallbackIDCounter, cb));
@ -180,7 +210,8 @@ bool Communication::removeMessageCallback(int id) {
} }
} }
std::shared_ptr<Message> Communication::waitForMessageSync(std::function<bool(void)> onceWaitingDo, MessageFilter f, std::chrono::milliseconds timeout) { std::shared_ptr<Message> Communication::waitForMessageSync(std::function<bool(void)> onceWaitingDo,
const std::shared_ptr<MessageFilter>& f, std::chrono::milliseconds timeout) {
std::mutex m; std::mutex m;
std::condition_variable cv; std::condition_variable cv;
std::shared_ptr<Message> returnedMessage; std::shared_ptr<Message> returnedMessage;

View File

@ -3,6 +3,8 @@
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/communication/message/readsettingsmessage.h" #include "icsneo/communication/message/readsettingsmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
@ -11,6 +13,8 @@
#include "icsneo/communication/packet/flexraypacket.h" #include "icsneo/communication/packet/flexraypacket.h"
#include "icsneo/communication/packet/iso9141packet.h" #include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/versionpacket.h" #include "icsneo/communication/packet/versionpacket.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
#include <iostream> #include <iostream>
using namespace icsneo; using namespace icsneo;
@ -24,7 +28,7 @@ uint64_t Decoder::GetUInt64FromLEBytes(const uint8_t* bytes) {
bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) { bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Packet>& packet) {
switch(packet->network.getType()) { switch(packet->network.getType()) {
case Network::Type::Ethernet: case Network::Type::Ethernet: {
result = HardwareEthernetPacket::DecodeToMessage(packet->data, report); result = HardwareEthernetPacket::DecodeToMessage(packet->data, report);
if(!result) { if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
@ -33,9 +37,11 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; EthernetMessage& eth = *static_cast<EthernetMessage*>(result.get());
result->network = packet->network; eth.timestamp *= timestampResolution;
eth.network = packet->network;
return true; return true;
}
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
@ -49,10 +55,28 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; result->timestamp *= timestampResolution;
result->network = packet->network;
switch(result->type) {
case Message::Type::Frame: {
CANMessage& can = *static_cast<CANMessage*>(result.get());
can.network = packet->network;
break;
}
case Message::Type::CANErrorCount: {
CANErrorCountMessage& can = *static_cast<CANErrorCountMessage*>(result.get());
can.network = packet->network;
break;
}
default: {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // An unknown type was returned, the packet was malformed
}
}
return true; return true;
} }
case Network::Type::FlexRay: { case Network::Type::FlexRay: {
@ -66,10 +90,12 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; FlexRayMessage& fr = *static_cast<FlexRayMessage*>(result.get());
result->network = packet->network; fr.timestamp *= timestampResolution;
fr.network = packet->network;
return true; return true;
} }
case Network::Type::ISO9141: { case Network::Type::ISO9141: {
@ -84,25 +110,24 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; ISO9141Message& iso = *static_cast<ISO9141Message*>(result.get());
result->network = packet->network; iso.timestamp *= timestampResolution;
iso.network = packet->network;
return true; return true;
} }
case Network::Type::Internal: { case Network::Type::Internal: {
switch(packet->network.getNetID()) { switch(packet->network.getNetID()) {
case Network::NetID::Reset_Status: { case Network::NetID::Reset_Status: {
if(packet->data.size() < sizeof(HardwareResetStatusPacket)) { // We can deal with not having the last two fields (voltage and temperature)
if(packet->data.size() < (sizeof(HardwareResetStatusPacket) - (sizeof(uint16_t) * 2))) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; return false;
} }
HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data(); HardwareResetStatusPacket* data = (HardwareResetStatusPacket*)packet->data.data();
auto msg = std::make_shared<ResetStatusMessage>(); auto msg = std::make_shared<ResetStatusMessage>();
msg->network = packet->network;
msg->mainLoopTime = data->main_loop_time_25ns * 25; msg->mainLoopTime = data->main_loop_time_25ns * 25;
msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25; msg->maxMainLoopTime = data->max_main_loop_time_25ns * 25;
msg->busVoltage = data->busVoltage;
msg->deviceTemperature = data->deviceTemperature;
msg->justReset = data->status.just_reset; msg->justReset = data->status.just_reset;
msg->comEnabled = data->status.com_enabled; msg->comEnabled = data->status.com_enabled;
msg->cmRunning = data->status.cm_is_running; msg->cmRunning = data->status.cm_is_running;
@ -116,6 +141,10 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
msg->cmTooBig = data->status.cm_too_big; msg->cmTooBig = data->status.cm_too_big;
msg->hidUsbState = data->status.hidUsbState; msg->hidUsbState = data->status.hidUsbState;
msg->fpgaUsbState = data->status.fpgaUsbState; msg->fpgaUsbState = data->status.fpgaUsbState;
if(packet->data.size() >= sizeof(HardwareResetStatusPacket)) {
msg->busVoltage = data->busVoltage;
msg->deviceTemperature = data->deviceTemperature;
}
result = msg; result = msg;
return true; return true;
} }
@ -124,9 +153,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
// They come in as CAN but we will handle them in the device rather than // They come in as CAN but we will handle them in the device rather than
// passing them onto the user. // passing them onto the user.
if(packet->data.size() < 24) { if(packet->data.size() < 24) {
result = std::make_shared<Message>(); auto rawmsg = std::make_shared<RawMessage>(Network::NetID::Device);
result->network = packet->network; result = rawmsg;
result->data = packet->data; rawmsg->data = packet->data;
return true; return true;
} }
@ -135,17 +164,33 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error); report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed return false; // A nullptr was returned, the packet was malformed
} }
// Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000 // Timestamps are in (resolution) ns increments since 1/1/2007 GMT 00:00:00.0000
// The resolution depends on the device // The resolution depends on the device
result->timestamp *= timestampResolution; auto* raw = dynamic_cast<RawMessage*>(result.get());
result->network = packet->network; if(raw == nullptr) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // A nullptr was returned, the packet was malformed
}
raw->timestamp *= timestampResolution;
raw->network = packet->network;
return true; return true;
} }
case Network::NetID::DeviceStatus: { case Network::NetID::DeviceStatus: {
result = std::make_shared<Message>();
result->network = packet->network;
// Just pass along the data, the device needs to handle this itself // Just pass along the data, the device needs to handle this itself
result->data = packet->data; result = std::make_shared<RawMessage>(packet->network, packet->data);
return true;
}
case Network::NetID::NeoMemorySDRead: {
if(packet->data.size() != 512 + sizeof(uint32_t)) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false; // Should get enough data for a start address and sector
}
const auto msg = std::make_shared<NeoReadMemorySDMessage>();
result = msg;
msg->startAddress = *reinterpret_cast<uint32_t*>(packet->data.data());
msg->data.insert(msg->data.end(), packet->data.begin() + 4, packet->data.end());
return true; return true;
} }
case Network::NetID::FlexRayControl: { case Network::NetID::FlexRayControl: {
@ -161,7 +206,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
switch((Command)packet->data[0]) { switch((Command)packet->data[0]) {
case Command::RequestSerialNumber: { case Command::RequestSerialNumber: {
auto msg = std::make_shared<SerialNumberMessage>(); auto msg = std::make_shared<SerialNumberMessage>();
msg->network = packet->network;
uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1); uint64_t serial = GetUInt64FromLEBytes(packet->data.data() + 1);
// The device sends 64-bits of serial number, but we never use more than 32-bits. // The device sends 64-bits of serial number, but we never use more than 32-bits.
msg->deviceSerial = Device::SerialNumToString((uint32_t)serial); msg->deviceSerial = Device::SerialNumToString((uint32_t)serial);
@ -194,7 +238,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
default: default:
auto msg = std::make_shared<Main51Message>(); auto msg = std::make_shared<Main51Message>();
msg->network = packet->network;
msg->command = Command(packet->data[0]); msg->command = Command(packet->data[0]);
msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end()); msg->data.insert(msg->data.begin(), packet->data.begin() + 1, packet->data.end());
result = msg; result = msg;
@ -218,7 +261,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
case Network::NetID::ReadSettings: { case Network::NetID::ReadSettings: {
auto msg = std::make_shared<ReadSettingsMessage>(); auto msg = std::make_shared<ReadSettingsMessage>();
msg->network = packet->network;
msg->response = ReadSettingsMessage::Response(packet->data[0]); msg->response = ReadSettingsMessage::Response(packet->data[0]);
if(msg->response == ReadSettingsMessage::Response::OK) { if(msg->response == ReadSettingsMessage::Response::OK) {
@ -236,6 +278,22 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
result = msg; result = msg;
return true; return true;
} }
case Network::NetID::LogicalDiskInfo: {
result = LogicalDiskInfoPacket::DecodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
case Network::NetID::EthPHYControl: {
result = HardwareEthernetPhyRegisterPacket::DecodeToMessage(packet->data, report);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::EventWarning);
return false;
}
return true;
}
default: default:
break; break;
} }
@ -243,9 +301,6 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
} }
// For the moment other types of messages will automatically be decoded as raw messages // For the moment other types of messages will automatically be decoded as raw messages
auto msg = std::make_shared<Message>(); result = std::make_shared<RawMessage>(packet->network, packet->data);
msg->network = packet->network;
msg->data = packet->data;
result = msg;
return true; return true;
} }

View File

@ -1,5 +1,11 @@
#include "icsneo/communication/driver.h" #include "icsneo/communication/driver.h"
//#define ICSNEO_DRIVER_DEBUG_PRINTS
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
#include <iostream>
#include <iomanip>
#endif
using namespace icsneo; using namespace icsneo;
bool Driver::read(std::vector<uint8_t>& bytes, size_t limit) { bool Driver::read(std::vector<uint8_t>& bytes, size_t limit) {
@ -35,6 +41,18 @@ bool Driver::readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds tim
bytes.resize(actuallyRead); bytes.resize(actuallyRead);
#ifdef ICSNEO_DRIVER_DEBUG_PRINTS
if(actuallyRead > 0) {
std::cout << "Read data: (" << actuallyRead << ')' << std::hex << std::endl;
for(int i = 0; i < actuallyRead; i += 16) {
for(int j = 0; j < std::min<int>(actuallyRead - i, 16); j++)
std::cout << std::setw(2) << std::setfill('0') << uint32_t(bytes[i+j]) << ' ';
std::cout << std::endl;
}
std::cout << std::dec << std::endl;
}
#endif
return actuallyRead > 0; return actuallyRead > 0;
} }
@ -45,17 +63,18 @@ bool Driver::write(const std::vector<uint8_t>& bytes) {
} }
if(writeBlocks) { if(writeBlocks) {
if(writeQueue.size_approx() > writeQueueSize) if(writeQueueFull()) {
while(writeQueue.size_approx() > (writeQueueSize * 3 / 4)) while(writeQueueAlmostFull()) // Wait until we have some decent amount of space
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
} else { } else {
if(writeQueue.size_approx() > writeQueueSize) { if(writeQueueFull()) {
report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error); report(APIEvent::Type::TransmitBufferFull, APIEvent::Severity::Error);
return false; return false;
} }
} }
bool ret = writeQueue.enqueue(WriteOperation(bytes)); const bool ret = writeInternal(bytes);
if(!ret) if(!ret)
report(APIEvent::Type::Unknown, APIEvent::Severity::Error); report(APIEvent::Type::Unknown, APIEvent::Severity::Error);

View File

@ -4,15 +4,26 @@
#include "icsneo/communication/packet/ethernetpacket.h" #include "icsneo/communication/packet/ethernetpacket.h"
#include "icsneo/communication/packet/iso9141packet.h" #include "icsneo/communication/packet/iso9141packet.h"
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/ethphymessage.h"
using namespace icsneo; using namespace icsneo;
bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) { bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message) {
bool shortFormat = false; bool shortFormat = false;
bool useResultAsBuffer = false; // Otherwise it's expected that we use message->data std::vector<uint8_t>* buffer = &result;
uint16_t netid = 0;
result.clear(); result.clear();
switch(message->network.getType()) { switch(message->type) {
case Message::Type::Frame: {
auto frame = std::dynamic_pointer_cast<Frame>(message);
// Frame uses frame->data as the buffer unless directed otherwise
buffer = &frame->data;
netid = uint16_t(frame->network.getNetID());
switch(frame->network.getType()) {
case Network::Type::Ethernet: { case Network::Type::Ethernet: {
auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message); auto ethmsg = std::dynamic_pointer_cast<EthernetMessage>(message);
if(!ethmsg) { if(!ethmsg) {
@ -20,7 +31,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
return false; // The message was not a properly formed EthernetMessage return false; // The message was not a properly formed EthernetMessage
} }
useResultAsBuffer = true; buffer = &result;
if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report)) if(!HardwareEthernetPacket::EncodeFromMessage(*ethmsg, result, report))
return false; return false;
@ -40,7 +51,7 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
return false; // This device does not support CAN FD return false; // This device does not support CAN FD
} }
useResultAsBuffer = true; buffer = &result;
if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report)) if(!HardwareCANPacket::EncodeFromMessage(*canmsg, result, report))
return false; // The CANMessage was malformed return false; // The CANMessage was malformed
@ -58,70 +69,102 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer); return HardwareISO9141Packet::EncodeFromMessage(*isomsg, result, report, packetizer);
} // End of Network::Type::ISO9141 } // End of Network::Type::ISO9141
default: default:
switch(message->network.getNetID()) { report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false;
}
break;
}
case Message::Type::RawMessage: {
auto raw = std::dynamic_pointer_cast<RawMessage>(message);
// Raw message uses raw->data as the buffer unless directed otherwise
buffer = &raw->data;
netid = uint16_t(raw->network.getNetID());
switch(raw->network.getNetID()) {
case Network::NetID::Device: case Network::NetID::Device:
shortFormat = true; shortFormat = true;
break; break;
case Network::NetID::Main51: {
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
if(!m51msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Main51Message
}
if(!m51msg->forceShortFormat) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(message->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
size += 1; // Main51 Command
message->data.insert(message->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)m51msg->command
});
result = packetizer.packetWrap(message->data, shortFormat);
return true;
} else {
message->data.insert(message->data.begin(), { uint8_t(m51msg->command) });
shortFormat = true;
}
break;
}
case Network::NetID::RED_OLDFORMAT: { case Network::NetID::RED_OLDFORMAT: {
// See the decoder for an explanation // See the decoder for an explanation
// We expect the network byte to be populated already in data, but not the length // We expect the network byte to be populated already in data, but not the length
uint16_t length = uint16_t(message->data.size()) - 1; uint16_t length = uint16_t(raw->data.size()) - 1;
message->data.insert(message->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)}); raw->data.insert(raw->data.begin(), {(uint8_t)length, (uint8_t)(length >> 8)});
break; break;
} }
default: default:
report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error); report(APIEvent::Type::UnexpectedNetworkType, APIEvent::Severity::Error);
return false; return false;
} }
break;
}
case Message::Type::Main51: {
auto m51msg = std::dynamic_pointer_cast<Main51Message>(message);
if(!m51msg) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; // The message was not a properly formed Main51Message
}
buffer = &m51msg->data;
netid = uint16_t(Network::NetID::Main51);
if(!m51msg->forceShortFormat) {
// Main51 can be sent as a long message without setting the NetID to RED first
// Size in long format is the size of the entire packet
// So +1 for AA header, +1 for short format header, and +2 for long format size
uint16_t size = uint16_t(m51msg->data.size()) + 1 + 1 + 2;
size += 1; // Even though we are not including the NetID bytes, the device expects them to be counted in the length
size += 1; // Main51 Command
m51msg->data.insert(m51msg->data.begin(), {
(uint8_t)Network::NetID::Main51, // 0x0B for long message
(uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8),
(uint8_t)m51msg->command
});
result = packetizer.packetWrap(m51msg->data, shortFormat);
return true;
} else {
m51msg->data.insert(m51msg->data.begin(), { uint8_t(m51msg->command) });
shortFormat = true;
}
break;
}
case Message::Type::EthernetPhyRegister: {
if(!supportEthPhy) {
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
return false;
}
auto ethPhyMessage = std::dynamic_pointer_cast<EthPhyMessage>(message);
if(!ethPhyMessage) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
if(!HardwareEthernetPhyRegisterPacket::EncodeFromMessage(*ethPhyMessage, result, report))
return false;
break;
}
break;
} }
// Early returns may mean we don't reach this far, check the type you're concerned with // Early returns may mean we don't reach this far, check the type you're concerned with
auto& buffer = useResultAsBuffer ? result : message->data;
if(shortFormat) { if(shortFormat) {
buffer.insert(buffer.begin(), (uint8_t(buffer.size()) << 4) | uint8_t(message->network.getNetID())); buffer->insert(buffer->begin(), (uint8_t(buffer->size()) << 4) | uint8_t(netid));
} else { } else {
// Size in long format is the size of the entire packet // Size for the host-to-device long format is the size of the entire packet + 1
// So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID // So +1 for AA header, +1 for short format header, +2 for long format size, and +2 for long format NetID
uint16_t size = uint16_t(buffer.size()) + 1 + 1 + 2 + 2; // Then an extra +1, due to a firmware idiosyncrasy
buffer.insert(buffer.begin(), { uint16_t size = uint16_t(buffer->size()) + 1 + 1 + 2 + 2 + 1;
buffer->insert(buffer->begin(), {
(uint8_t)Network::NetID::RED, // 0x0C for long message (uint8_t)Network::NetID::RED, // 0x0C for long message
(uint8_t)size, // Size, little endian 16-bit (uint8_t)size, // Size, little endian 16-bit
(uint8_t)(size >> 8), (uint8_t)(size >> 8),
(uint8_t)message->network.getNetID(), // NetID, little endian 16-bit (uint8_t)netid, // NetID, little endian 16-bit
(uint8_t)(uint16_t(message->network.getNetID()) >> 8) (uint8_t)(netid >> 8)
}); });
} }
result = packetizer.packetWrap(buffer, shortFormat); result = packetizer.packetWrap(*buffer, shortFormat);
return true; return true;
} }
@ -133,20 +176,19 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
* In this case, command 0x06 is SetLEDState. * In this case, command 0x06 is SetLEDState.
* This old command type is not really used anywhere else. * This old command type is not really used anywhere else.
*/ */
msg = std::make_shared<Message>(); auto canmsg = std::make_shared<RawMessage>(Network::NetID::Device);
msg = canmsg;
if(arguments.empty()) { if(arguments.empty()) {
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error); report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false; return false;
} }
msg->network = Network::NetID::Device; canmsg->data.reserve(3);
msg->data.reserve(3); canmsg->data.push_back(0x00);
msg->data.push_back(0x00); canmsg->data.push_back(0x06); // SetLEDState
msg->data.push_back(0x06); // SetLEDState canmsg->data.push_back(arguments.at(0)); // See Device::LEDState
msg->data.push_back(arguments.at(0)); // See Device::LEDState
} else { } else {
auto m51msg = std::make_shared<Main51Message>(); auto m51msg = std::make_shared<Main51Message>();
msg = m51msg; msg = m51msg;
msg->network = Network::NetID::Main51;
m51msg->command = cmd; m51msg->command = cmd;
switch(cmd) { switch(cmd) {
case Command::ReadSettings: case Command::ReadSettings:
@ -155,13 +197,14 @@ bool Encoder::encode(const Packetizer& packetizer, std::vector<uint8_t>& result,
case Command::EnableNetworkCommunicationEx: case Command::EnableNetworkCommunicationEx:
case Command::GetMainVersion: case Command::GetMainVersion:
case Command::GetSecondaryVersions: case Command::GetSecondaryVersions:
case Command::NeoReadMemory:
// There is a firmware handling idiosyncrasy with these commands // There is a firmware handling idiosyncrasy with these commands
// They must be encoded in the short format // They must be encoded in the short format
m51msg->forceShortFormat = true; m51msg->forceShortFormat = true;
default: default:
break; break;
} }
msg->data.insert(msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end())); m51msg->data.insert(m51msg->data.end(), std::make_move_iterator(arguments.begin()), std::make_move_iterator(arguments.end()));
} }
return encode(packetizer, result, msg); return encode(packetizer, result, msg);

View File

@ -2,41 +2,62 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <cstring> #include <cstring>
#include <cassert>
#include <iostream>
using namespace icsneo; using namespace icsneo;
#define MAX_PACKET_LEN (1490) // MTU - overhead const size_t EthernetPacketizer::MaxPacketLength = 1490; // MTU - overhead
static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const uint8_t BROADCAST_MAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
void EthernetPacketizer::inputDown(std::vector<uint8_t> bytes) { EthernetPacketizer::EthernetPacket& EthernetPacketizer::newSendPacket(bool first) {
EthernetPacket sendPacket; processedDownPackets.emplace_back();
std::copy(std::begin(hostMAC), std::end(hostMAC), std::begin(sendPacket.srcMAC)); EthernetPacket& ret = processedDownPackets.back();
std::copy(std::begin(deviceMAC), std::end(deviceMAC), std::begin(sendPacket.destMAC)); if(first) {
ret.packetNumber = sequenceDown++;
} else {
ret.firstPiece = false;
if(processedDownPackets.size() > 1)
ret.packetNumber = (processedDownPackets.rbegin() + 1)->packetNumber;
else
assert(false); // This should never be called with !first if there are no packets in the queue
}
std::copy(std::begin(hostMAC), std::end(hostMAC), std::begin(ret.srcMAC));
std::copy(std::begin(deviceMAC), std::end(deviceMAC), std::begin(ret.destMAC));
return ret;
}
sendPacket.packetNumber = sequenceDown++; void EthernetPacketizer::inputDown(std::vector<uint8_t> bytes, bool first) {
sendPacket.payload = std::move(bytes); EthernetPacket* sendPacket = nullptr;
if(first && !processedDownPackets.empty()) {
// We have some packets already, let's see if we can add this to the last one
if(processedDownPackets.back().payload.size() + bytes.size() <= MaxPacketLength)
sendPacket = &processedDownPackets.back();
}
if(sendPacket == nullptr)
sendPacket = &newSendPacket(first);
if(sendPacket->payload.empty())
sendPacket->payload = std::move(bytes);
else
sendPacket->payload.insert(sendPacket->payload.end(), bytes.begin(), bytes.end());
// Split packets larger than MTU // Split packets larger than MTU
std::vector<uint8_t> extraData; std::vector<uint8_t> extraData;
if(sendPacket.payload.size() > MAX_PACKET_LEN) { if(sendPacket->payload.size() > MaxPacketLength) {
extraData.insert(extraData.end(), sendPacket.payload.begin() + MAX_PACKET_LEN, sendPacket.payload.end()); extraData.insert(extraData.end(), sendPacket->payload.begin() + MaxPacketLength, sendPacket->payload.end());
sendPacket.payload.resize(MAX_PACKET_LEN); sendPacket->payload.resize(MaxPacketLength);
sendPacket.lastPiece = false; sendPacket->lastPiece = false;
} inputDown(std::move(extraData), false);
processedDownPackets.push_back(sendPacket.getBytestream());
if(!extraData.empty()) {
sendPacket.payload = std::move(extraData);
sendPacket.firstPiece = false;
sendPacket.lastPiece = true;
processedDownPackets.push_back(sendPacket.getBytestream());
} }
} }
std::vector< std::vector<uint8_t> > EthernetPacketizer::outputDown() { std::vector< std::vector<uint8_t> > EthernetPacketizer::outputDown() {
std::vector< std::vector<uint8_t> > ret = std::move(processedDownPackets); std::vector< std::vector<uint8_t> > ret;
ret.reserve(processedDownPackets.size());
for(auto&& packet : std::move(processedDownPackets))
ret.push_back(packet.getBytestream());
processedDownPackets.clear(); processedDownPackets.clear();
return ret; return ret;
} }
@ -54,7 +75,7 @@ bool EthernetPacketizer::inputUp(std::vector<uint8_t> bytes) {
memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0) memcmp(packet.destMAC, BROADCAST_MAC, sizeof(packet.destMAC)) != 0)
return false; // Packet is not addressed to us or broadcast return false; // Packet is not addressed to us or broadcast
if(memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0) if(!allowInPacketsFromAnyMAC && memcmp(packet.srcMAC, deviceMAC, sizeof(deviceMAC)) != 0)
return false; // Not a packet from the device we're concerned with return false; // Not a packet from the device we're concerned with
// Handle single packets // Handle single packets
@ -73,7 +94,7 @@ bool EthernetPacketizer::inputUp(std::vector<uint8_t> bytes) {
reassembling = true; reassembling = true;
reassemblingId = packet.packetNumber; reassemblingId = packet.packetNumber;
reassemblingData = std::move(bytes); reassemblingData = std::move(packet.payload);
return !processedUpBytes.empty(); // If there are other packets in the pipe return !processedUpBytes.empty(); // If there are other packets in the pipe
} }
@ -119,7 +140,7 @@ int EthernetPacketizer::EthernetPacket::loadBytestream(const std::vector<uint8_t
srcMAC[i] = bytestream[i + 6]; srcMAC[i] = bytestream[i + 6];
etherType = (bytestream[12] << 8) | bytestream[13]; etherType = (bytestream[12] << 8) | bytestream[13];
icsEthernetHeader = (bytestream[14] << 24) | (bytestream[15] << 16) | (bytestream[16] << 8) | bytestream[17]; icsEthernetHeader = (bytestream[14] << 24) | (bytestream[15] << 16) | (bytestream[16] << 8) | bytestream[17];
uint16_t payloadSize = bytestream[18] | (bytestream[19] << 8); payloadSize = bytestream[18] | (bytestream[19] << 8);
packetNumber = bytestream[20] | (bytestream[21] << 8); packetNumber = bytestream[20] | (bytestream[21] << 8);
uint16_t packetInfo = bytestream[22] | (bytestream[23] << 8); uint16_t packetInfo = bytestream[22] | (bytestream[23] << 8);
firstPiece = packetInfo & 1; firstPiece = packetInfo & 1;
@ -127,17 +148,15 @@ int EthernetPacketizer::EthernetPacket::loadBytestream(const std::vector<uint8_t
bufferHalfFull = (packetInfo >> 2) & 2; bufferHalfFull = (packetInfo >> 2) & 2;
payload = std::vector<uint8_t>(bytestream.begin() + 24, bytestream.end()); payload = std::vector<uint8_t>(bytestream.begin() + 24, bytestream.end());
size_t payloadActualSize = payload.size(); size_t payloadActualSize = payload.size();
if(payloadActualSize < payloadSize) if(payloadActualSize > payloadSize)
errorWhileDecodingFromBytestream = 1;
else
payload.resize(payloadSize); payload.resize(payloadSize);
return errorWhileDecodingFromBytestream; return errorWhileDecodingFromBytestream;
} }
std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const { std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
size_t payloadSize = payload.size(); uint16_t actualPayloadSize = uint16_t(payload.size());
std::vector<uint8_t> bytestream; std::vector<uint8_t> bytestream;
bytestream.reserve(6 + 6 + 2 + 4 + 2 + 2 + 2 + payloadSize); bytestream.reserve(6 + 6 + 2 + 4 + 2 + 2 + 2 + actualPayloadSize);
for(size_t i = 0; i < 6; i++) for(size_t i = 0; i < 6; i++)
bytestream.push_back(destMAC[i]); bytestream.push_back(destMAC[i]);
for(size_t i = 0; i < 6; i++) for(size_t i = 0; i < 6; i++)
@ -150,9 +169,10 @@ std::vector<uint8_t> EthernetPacketizer::EthernetPacket::getBytestream() const {
bytestream.push_back((uint8_t)(icsEthernetHeader >> 16)); bytestream.push_back((uint8_t)(icsEthernetHeader >> 16));
bytestream.push_back((uint8_t)(icsEthernetHeader >> 8)); bytestream.push_back((uint8_t)(icsEthernetHeader >> 8));
bytestream.push_back((uint8_t)(icsEthernetHeader)); bytestream.push_back((uint8_t)(icsEthernetHeader));
uint16_t declaredPayloadSize = payloadSize ? payloadSize : actualPayloadSize;
// The payload size comes next, it's little endian // The payload size comes next, it's little endian
bytestream.push_back((uint8_t)(payloadSize)); bytestream.push_back((uint8_t)(declaredPayloadSize));
bytestream.push_back((uint8_t)(payloadSize >> 8)); bytestream.push_back((uint8_t)(declaredPayloadSize >> 8));
// Packet number is little endian // Packet number is little endian
bytestream.push_back((uint8_t)(packetNumber)); bytestream.push_back((uint8_t)(packetNumber));
bytestream.push_back((uint8_t)(packetNumber >> 8)); bytestream.push_back((uint8_t)(packetNumber >> 8));

View File

@ -0,0 +1,50 @@
#include "icsneo/communication/message/ethphymessage.h"
namespace icsneo
{
bool EthPhyMessage::appendPhyMessage(bool writeEnable, bool clause45, uint8_t phyAddrOrPort, uint8_t pageOrDevice, uint16_t regAddr, uint16_t regVal, bool enabled)
{
auto msg = std::make_shared<PhyMessage>();
msg->Clause45Enable = clause45;
msg->Enabled = enabled;
msg->WriteEnable = writeEnable;
msg->version = 1u;
if( (FiveBits < phyAddrOrPort) ||
(clause45 && (FiveBits < pageOrDevice)) ||
(!clause45 && (FiveBits < regAddr)) )
{
return false;
}
if(clause45)
{
msg->clause45.port = phyAddrOrPort;
msg->clause45.device = pageOrDevice;
msg->clause45.regAddr = regAddr;
msg->clause45.regVal = regVal;
}
else
{
msg->clause22.phyAddr = phyAddrOrPort;
msg->clause22.page = pageOrDevice;
msg->clause22.regAddr = regAddr;
msg->clause22.regVal = regVal;
}
return appendPhyMessage(msg);
}
bool EthPhyMessage::appendPhyMessage(std::shared_ptr<PhyMessage> message)
{
if(message != nullptr)
{
messages.push_back(message);
return true;
}
return false;
}
size_t EthPhyMessage::getMessageCount() const
{
return messages.size();
}
}

View File

@ -64,9 +64,7 @@ std::vector<uint8_t> FlexRayControlMessage::BuildWriteMessageBufferArgs(
return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args); return BuildBaseControlArgs(controller, FlexRay::Opcode::WriteMessageBuffer, args);
} }
FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message() { FlexRayControlMessage::FlexRayControlMessage(const Packet& packet) : Message(Message::Type::FlexRayControl) {
network = Network::NetID::FlexRayControl;
if(packet.data.size() < 2) if(packet.data.size() < 2)
return; // huh? return; // huh?
controller = packet.data[0]; controller = packet.data[0];

View File

@ -1,24 +1,32 @@
#include "icsneo/communication/message/neomessage.h" #include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
using namespace icsneo; using namespace icsneo;
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) { neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// This function is not responsible for storing the message! // This function is not responsible for storing the message!
// Keep the shared_ptr around for the lifetime of the data access // Keep the shared_ptr around for the lifetime of the data access
const auto type = message->network.getType();
neomessage_t neomsg = {}; // Clear out the memory neomessage_t neomsg = {}; // Clear out the memory
neomsg.netid = (uint32_t)message->network.getNetID(); neomsg.messageType = (neomessagetype_t)message->type;
neomsg.type = (uint8_t)type;
neomsg.description = message->description;
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp; neomsg.timestamp = message->timestamp;
neomsg.status.globalError = message->error; switch (message->type)
neomsg.status.transmitMessage = message->transmitted; {
case Message::Type::Frame: {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<Frame>(message);
const auto netType = framemsg->network.getType();
frame.netid = (neonetid_t)framemsg->network.getNetID();
frame.type = (neonettype_t)netType;
frame.description = framemsg->description;
frame.length = framemsg->data.size();
frame.data = framemsg->data.data();
frame.timestamp = framemsg->timestamp;
frame.status.globalError = framemsg->error;
frame.status.transmitMessage = framemsg->transmitted;
switch(type) { switch(netType) {
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
@ -49,12 +57,28 @@ neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// TODO Implement others // TODO Implement others
break; break;
} }
break;
}
case Message::Type::CANErrorCount: {
neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message);
canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
canerror.status.canBusOff = canerrormsg->busOff;
canerror.netid = (neonetid_t)canerrormsg->network.getNetID();
canerror.type = (neonettype_t)canerrormsg->network.getType();
break;
}
default:
break;
}
return neomsg; return neomsg;
} }
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) { std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
const Network network = neomessage->netid; switch((Message::Type)neomessage->messageType) {
case Message::Type::Frame: {
const Network network = ((neomessage_frame_t*)neomessage)->netid;
switch(network.getType()) { switch(network.getType()) {
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
@ -65,6 +89,7 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
canmsg->description = can.description; canmsg->description = can.description;
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length); canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
canmsg->arbid = can.arbid; canmsg->arbid = can.arbid;
canmsg->dlcOnWire = can.dlcOnWire;
canmsg->isExtended = can.status.extendedFrame; canmsg->isExtended = can.status.extendedFrame;
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR; canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
canmsg->isCANFD = can.status.canfdFDF; canmsg->isCANFD = can.status.canfdFDF;
@ -80,8 +105,12 @@ std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t*
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length); ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
return ethmsg; return ethmsg;
} }
default: default: break;
// TODO Implement others }
break;
}
default: break;
}
return std::shared_ptr<Message>(); return std::shared_ptr<Message>();
}
} }

View File

@ -2,6 +2,7 @@
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/communication/decoder.h" #include "icsneo/communication/decoder.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
using namespace icsneo; using namespace icsneo;
@ -134,6 +135,12 @@ void MultiChannelCommunication::hidReadTask() {
if(numVnets >= 3) if(numVnets >= 3)
currentQueue = &vnetQueues[2]; currentQueue = &vnetQueues[2];
break; break;
case CommandType::SDCC1_to_HostPC: {
auto msg = std::make_shared<NeoReadMemorySDMessage>();
std::swap(msg->data, payloadBytes);
dispatchMessage(msg);
break;
}
} }
if(currentQueue == nullptr) { if(currentQueue == nullptr) {

View File

@ -1,34 +1,76 @@
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/platform/optional.h" #include "icsneo/platform/optional.h"
using namespace icsneo; using namespace icsneo;
static optional<uint8_t> CANFD_DLCToLength(uint8_t length) { static optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
if (length < 8) if (length <= 8)
return length; return length;
if (fd) {
switch(length) { switch(length) {
case 0x9: case 0x9:
return 12; return uint8_t(12);
case 0xa: case 0xa:
return 16; return uint8_t(16);
case 0xb: case 0xb:
return 20; return uint8_t(20);
case 0xc: case 0xc:
return 24; return uint8_t(24);
case 0xd: case 0xd:
return 32; return uint8_t(32);
case 0xe: case 0xe:
return 48; return uint8_t(48);
case 0xf: case 0xf:
return 64; return uint8_t(64);
} }
}
return nullopt; return nullopt;
} }
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) { static optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
{
if (dataLength <= 8)
return uint8_t(dataLength);
if (fd) {
if (dataLength <= 12)
return uint8_t(0x9);
else if (dataLength <= 16)
return uint8_t(0xA);
else if (dataLength <= 20)
return uint8_t(0xB);
else if (dataLength <= 24)
return uint8_t(0xC);
else if (dataLength <= 32)
return uint8_t(0xD);
else if (dataLength <= 48)
return uint8_t(0xE);
else if (dataLength <= 64)
return uint8_t(0xF);
}
return nullopt;
}
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data(); const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting
const bool busOff = data->data[0] & 0b00100000;
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
return msg;
} else { // CAN Frame
auto msg = std::make_shared<CANMessage>(); auto msg = std::make_shared<CANMessage>();
// Arb ID // Arb ID
@ -52,7 +94,7 @@ std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector
msg->isCANFD = true; msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI; msg->errorStateIndicator = data->header.ESI;
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(length); const optional<uint8_t> lenFromDLC = CAN_DLCToLength(length, true);
if (lenFromDLC) if (lenFromDLC)
length = *lenFromDLC; length = *lenFromDLC;
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8 } else if(length > 8) { // This is a standard CAN frame with a length of more than 8
@ -82,6 +124,7 @@ std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector
return msg; return msg;
} }
}
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) { bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
if(message.isCANFD && message.isRemote) { if(message.isCANFD && message.isRemote) {
@ -90,11 +133,13 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
} }
const size_t dataSize = message.data.size(); const size_t dataSize = message.data.size();
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD)) { optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, message.isCANFD);
if (!dlc.has_value()) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error); report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol return false; // Too much data for the protocol
} }
if (message.dlcOnWire != 0) {
if(message.dlcOnWire > 0xf) { if(message.dlcOnWire > 0xf) {
// The DLC is only a nibble // The DLC is only a nibble
// It is actually possible to transmit a standard CAN frame with a DLC > 8 // It is actually possible to transmit a standard CAN frame with a DLC > 8
@ -105,100 +150,21 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
return false; return false;
} }
uint8_t lengthNibble = uint8_t(message.data.size()); if (message.dlcOnWire < *dlc) {
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(message.dlcOnWire);
if (lenFromDLC.has_value() && *lenFromDLC != 0) {
if (*lenFromDLC < lengthNibble) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error); report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; return false;
} }
if (*lenFromDLC > lengthNibble) if (message.dlcOnWire > *dlc)
lengthNibble = *lenFromDLC; dlc = message.dlcOnWire;
} }
uint8_t paddingBytes = 0; // The only way this fails is if we're transmitting a DLC > 8 on standard CAN
if(lengthNibble > 8) { const uint8_t paddedLength = CAN_DLCToLength(*dlc, message.isCANFD).value_or(8);
switch(lengthNibble) { const uint8_t paddingBytes = uint8_t(paddedLength - dataSize);
case 9: paddingBytes++;
case 10: paddingBytes++;
case 11: paddingBytes++;
case 12:
lengthNibble = 0x9;
break;
case 13: paddingBytes++;
case 14: paddingBytes++;
case 15: paddingBytes++;
case 16:
lengthNibble = 0xA;
break;
case 17: paddingBytes++;
case 18: paddingBytes++;
case 19: paddingBytes++;
case 20:
lengthNibble = 0xB;
break;
case 21: paddingBytes++;
case 22: paddingBytes++;
case 23: paddingBytes++;
case 24:
lengthNibble = 0xC;
break;
case 25: paddingBytes++;
case 26: paddingBytes++;
case 27: paddingBytes++;
case 28: paddingBytes++;
case 29: paddingBytes++;
case 30: paddingBytes++;
case 31: paddingBytes++;
case 32:
lengthNibble = 0xD;
break;
case 33: paddingBytes++;
case 34: paddingBytes++;
case 35: paddingBytes++;
case 36: paddingBytes++;
case 37: paddingBytes++;
case 38: paddingBytes++;
case 39: paddingBytes++;
case 40: paddingBytes++;
case 41: paddingBytes++;
case 42: paddingBytes++;
case 43: paddingBytes++;
case 44: paddingBytes++;
case 45: paddingBytes++;
case 46: paddingBytes++;
case 47: paddingBytes++;
case 48:
lengthNibble = 0xE;
break;
case 49: paddingBytes++;
case 50: paddingBytes++;
case 51: paddingBytes++;
case 52: paddingBytes++;
case 53: paddingBytes++;
case 54: paddingBytes++;
case 55: paddingBytes++;
case 56: paddingBytes++;
case 57: paddingBytes++;
case 58: paddingBytes++;
case 59: paddingBytes++;
case 60: paddingBytes++;
case 61: paddingBytes++;
case 62: paddingBytes++;
case 63: paddingBytes++;
case 64:
lengthNibble = 0xF;
break;
default:
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // CAN FD frame may have had an incorrect byte count
}
}
// Pre-allocate as much memory as we will possibly need for speed // Pre-allocate as much memory as we will possibly need for speed
result.reserve(17 + dataSize + paddingBytes); result.reserve(16 + dataSize + paddingBytes);
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF)); result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
@ -233,7 +199,7 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
// Status and DLC bits // Status and DLC bits
if(message.isCANFD) { if(message.isCANFD) {
result.push_back(0x0F); // FD Frame result.push_back(0x0F); // FD Frame
uint8_t fdStatusByte = lengthNibble; uint8_t fdStatusByte = *dlc;
if(message.baudrateSwitch) if(message.baudrateSwitch)
fdStatusByte |= 0x80; // BRS status bit fdStatusByte |= 0x80; // BRS status bit
// The firmware does not yet support transmitting ESI // The firmware does not yet support transmitting ESI
@ -241,13 +207,12 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
} else { } else {
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable // TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0; uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
result.push_back((statusNibble << 4) | lengthNibble); result.push_back((statusNibble << 4) | *dlc);
} }
// Now finally the payload // Now finally the payload
result.insert(result.end(), message.data.begin(), message.data.end()); result.insert(result.end(), message.data.begin(), message.data.end());
result.resize(result.size() + paddingBytes); result.resize(result.size() + paddingBytes);
result.push_back(0);
// Fill in the length byte from earlier // Fill in the length byte from earlier
result[0] |= result.size() << 4; result[0] |= result.size() << 4;

View File

@ -0,0 +1,106 @@
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/packetizer.h"
#include <memory>
#include <cstdint>
#include <iostream>
namespace icsneo
{
std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
if(bytestream.empty() || (bytestream.size() < sizeof(PhyRegisterHeader_t)))
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullptr;
}
auto msg = std::make_shared<EthPhyMessage>();
const PhyRegisterHeader_t* pHeader = reinterpret_cast<const PhyRegisterHeader_t*>(bytestream.data());
const size_t numEntries = static_cast<size_t>(pHeader->numEntries);
if(
(PhyPacketVersion == pHeader->version) &&
(sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) &&
(numEntries <= MaxPhyEntries) &&
((bytestream.size() - sizeof(PhyRegisterHeader_t))
== (sizeof(PhyRegisterPacket_t) * numEntries))
)
{
msg->messages.reserve(numEntries);
const PhyRegisterPacket_t* pFirstEntry = reinterpret_cast<const PhyRegisterPacket_t*>(bytestream.data() + sizeof(PhyRegisterHeader_t));
for(size_t entryIdx{0}; entryIdx < numEntries; ++entryIdx)
{
const PhyRegisterPacket_t* pEntry = (pFirstEntry + entryIdx);
auto phyMessage = std::make_shared<PhyMessage>();
phyMessage->Enabled = (pEntry->Enabled != 0u);
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
phyMessage->Clause45Enable = (pEntry->Clause45Enable != 0u);
phyMessage->version = static_cast<uint8_t>(pEntry->version);
if(phyMessage->Clause45Enable)
phyMessage->clause45 = pEntry->clause45;
else
phyMessage->clause22 = pEntry->clause22;
msg->messages.push_back(phyMessage);
}
}
return msg;
}
bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report)
{
const size_t messageCount = message.getMessageCount();
if(!messageCount)
{
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
else if (messageCount > MaxPhyEntries)
{
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
auto byteSize = (messageCount * sizeof(PhyRegisterPacket_t)) + sizeof(PhyRegisterHeader_t);
bytestream.reserve(byteSize);
bytestream.push_back(static_cast<uint8_t>(messageCount & 0xFF));
bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF));
bytestream.push_back(PhyPacketVersion);
bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t)));
for(auto& phyMessage : message.messages)
{
PhyRegisterPacket_t tempPacket;
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
tempPacket.version = (phyMessage->version & 0xF);
if(phyMessage->Clause45Enable)
{
if( (FiveBits < phyMessage->clause45.port) ||
(FiveBits < phyMessage->clause45.device) )
{
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
tempPacket.Clause45Enable = 0x1u;
tempPacket.clause45.port = phyMessage->clause45.port;
tempPacket.clause45.device = phyMessage->clause45.device;
tempPacket.clause45.regAddr = phyMessage->clause45.regAddr;
tempPacket.clause45.regVal = phyMessage->clause45.regVal;
}
else
{
if( (FiveBits < phyMessage->clause22.phyAddr) ||
(FiveBits < phyMessage->clause22.regAddr) )
{
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
tempPacket.Clause45Enable = 0x0u;
tempPacket.clause22.phyAddr = phyMessage->clause22.phyAddr;
tempPacket.clause22.page = phyMessage->clause22.page;
tempPacket.clause22.regAddr = phyMessage->clause22.regAddr;
tempPacket.clause22.regVal = phyMessage->clause22.regVal;
}
uint8_t* pktPtr = reinterpret_cast<uint8_t*>(&tempPacket);
bytestream.insert(bytestream.end(), pktPtr, pktPtr + sizeof(PhyRegisterPacket_t));
}
return true;
}
}

View File

@ -27,7 +27,7 @@ bool HardwareISO9141Packet::EncodeFromMessage(const ISO9141Message& message, std
const uint8_t maxSize = (firstPacket ? 9 : 12); const uint8_t maxSize = (firstPacket ? 9 : 12);
uint8_t currentSize = maxSize; uint8_t currentSize = maxSize;
if(bytesToSend - currentStart < maxSize) if(bytesToSend - currentStart < maxSize)
currentSize = bytesToSend - currentStart; currentSize = (uint8_t)(bytesToSend - currentStart);
packet.insert(packet.begin(), { packet.insert(packet.begin(), {
(uint8_t)Network::NetID::RED, // 0x0C for long message (uint8_t)Network::NetID::RED, // 0x0C for long message
@ -75,7 +75,7 @@ bool HardwareISO9141Packet::EncodeFromMessage(const ISO9141Message& message, std
} }
std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareISO9141Packet* data = (const HardwareISO9141Packet*)bytestream.data(); const HardwareISO9141Packet& packet = *reinterpret_cast<const HardwareISO9141Packet*>(bytestream.data());
if(!mMsg) { if(!mMsg) {
mMsg = std::make_shared<ISO9141Message>(); mMsg = std::make_shared<ISO9141Message>();
@ -84,8 +84,8 @@ std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(
mGotPackets++; mGotPackets++;
const bool morePacketsComing = data->c3.frm == 0; const bool morePacketsComing = packet.c3.frm == 0;
const uint8_t bytesInCurrentMessage = data->c3.len; const uint8_t bytesInCurrentMessage = packet.c3.len;
if(mMsg->data.size() + bytesInCurrentMessage > 500) { if(mMsg->data.size() + bytesInCurrentMessage > 500) {
mMsg.reset(); mMsg.reset();
return std::shared_ptr<ISO9141Message>(); return std::shared_ptr<ISO9141Message>();
@ -93,9 +93,9 @@ std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(
// This timestamp is raw off the device (in timestampResolution increments) // This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments // Decoder will fix as it has information about the timestampResolution increments
mMsg->timestamp = data->timestamp.TS; mMsg->timestamp = packet.timestamp.TS;
auto* dataStart = data->data; auto* dataStart = packet.data;
if(mGotPackets == 1) { if(mGotPackets == 1) {
// Header // Header
if(bytesInCurrentMessage < 3) { if(bytesInCurrentMessage < 3) {
@ -103,31 +103,31 @@ std::shared_ptr<ISO9141Message> HardwareISO9141Packet::Decoder::decodeToMessage(
return std::shared_ptr<ISO9141Message>(); return std::shared_ptr<ISO9141Message>();
} }
std::copy(data->data, data->data + 3, mMsg->header.begin()); std::copy(packet.data, packet.data + 3, mMsg->header.begin());
dataStart += 3; dataStart += 3;
} }
// Data // Data
mMsg->data.insert(mMsg->data.end(), dataStart, data->data + (bytesInCurrentMessage > 8 ? 8 : bytesInCurrentMessage)); mMsg->data.insert(mMsg->data.end(), dataStart, packet.data + (bytesInCurrentMessage > 8 ? 8 : bytesInCurrentMessage));
if(bytesInCurrentMessage > 8) if(bytesInCurrentMessage > 8)
mMsg->data.push_back(data->c1.d8); mMsg->data.push_back(packet.c1.d8);
if(bytesInCurrentMessage > 9) if(bytesInCurrentMessage > 9)
mMsg->data.push_back(data->c2.d9); mMsg->data.push_back(packet.c2.d9);
if(bytesInCurrentMessage > 10) if(bytesInCurrentMessage > 10)
mMsg->data.push_back(data->c2.d10); mMsg->data.push_back(packet.c2.d10);
if(bytesInCurrentMessage > 11) if(bytesInCurrentMessage > 11)
mMsg->data.push_back(data->c3.d11); mMsg->data.push_back(packet.c3.d11);
if(morePacketsComing) if(morePacketsComing)
return std::shared_ptr<ISO9141Message>(); return std::shared_ptr<ISO9141Message>();
mMsg->transmitted = data->c1.tx; mMsg->transmitted = packet.c1.tx;
mMsg->isInit = data->c3.init; mMsg->isInit = packet.c3.init;
mMsg->framingError = data->c1.options & 0x1; mMsg->framingError = packet.c1.options & 0x1;
mMsg->overflowError = data->c1.options & 0x2; mMsg->overflowError = packet.c1.options & 0x2;
mMsg->parityError = data->c1.options & 0x4; mMsg->parityError = packet.c1.options & 0x4;
mMsg->rxTimeoutError = data->c1.options & 0x8; mMsg->rxTimeoutError = packet.c1.options & 0x8;
mMsg->description = data->stats; mMsg->description = packet.stats;
auto ret = mMsg; auto ret = mMsg;
mMsg.reset(); mMsg.reset();

View File

@ -0,0 +1,12 @@
#include "icsneo/communication/packet/logicaldiskinfopacket.h"
using namespace icsneo;
std::shared_ptr<LogicalDiskInfoMessage> LogicalDiskInfoPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
// Make sure we have enough to read the packet length first
if(bytestream.size() < sizeof(LogicalDiskInfoPacket))
return {};
const LogicalDiskInfoPacket* packet = reinterpret_cast<const LogicalDiskInfoPacket*>(bytestream.data());
return std::make_shared<LogicalDiskInfoMessage>(packet->isConnected != 0, packet->numSectors, packet->hiddenSectors, packet->bytesPerSector);
}

View File

@ -6,7 +6,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
if(bytestream.size() < 3) // Not enough bytes to decode if(bytestream.size() < 3) // Not enough bytes to decode
return std::shared_ptr<VersionMessage>(); return std::shared_ptr<VersionMessage>();
auto msg = std::make_shared<VersionMessage>(true); auto msg = std::make_shared<VersionMessage>(VersionMessage::MainChip);
msg->Versions.emplace_back(); msg->Versions.emplace_back();
optional<DeviceAppVersion>& version = msg->Versions.back(); optional<DeviceAppVersion>& version = msg->Versions.back();
@ -18,7 +18,7 @@ std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeMainToMessage(const
} }
std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) { std::shared_ptr<VersionMessage> HardwareVersionPacket::DecodeSecondaryToMessage(const std::vector<uint8_t>& bytestream) {
auto msg = std::make_shared<VersionMessage>(false); auto msg = std::make_shared<VersionMessage>(VersionMessage::SecondaryChips);
size_t bytesLeft = bytestream.size(); size_t bytesLeft = bytestream.size();
if(bytesLeft) if(bytesLeft)

View File

@ -3,6 +3,8 @@
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/device/extensions/deviceextension.h" #include "icsneo/device/extensions/deviceextension.h"
#include "icsneo/platform/optional.h"
#include "icsneo/disk/fat.h"
#include <string.h> #include <string.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -117,19 +119,16 @@ std::pair<std::vector<std::shared_ptr<Message>>, bool> Device::getMessages() {
} }
bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) { bool Device::getMessages(std::vector<std::shared_ptr<Message>>& container, size_t limit, std::chrono::milliseconds timeout) {
// not open
if(!isOpen()) { if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false; return false;
} }
// not online
if(!isOnline()) { if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return false; return false;
} }
// not currently polling, throw error
if(!isMessagePollingEnabled()) { if(!isMessagePollingEnabled()) {
report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error); report(APIEvent::Type::DeviceNotCurrentlyPolling, APIEvent::Severity::Error);
return false; return false;
@ -245,19 +244,34 @@ bool Device::open(OpenFlags flags, OpenStatusHandler handler) {
while(!stopHeartbeatThread) { while(!stopHeartbeatThread) {
// Wait for 110ms for a possible heartbeat // Wait for 110ms for a possible heartbeat
std::this_thread::sleep_for(std::chrono::milliseconds(110)); std::this_thread::sleep_for(std::chrono::milliseconds(110));
if(!receivedMessage && !heartbeatSuppressed()) { if(receivedMessage) {
receivedMessage = false;
} else {
// Some communication, such as the bootloader and extractor interfaces, must
// redirect the input stream from the device as it will no longer be in the
// packet format we expect here. As a result, status updates will not reach
// us here and suppressDisconnects() must be used. We don't want to request
// a status and then redirect the stream, as we'll then be polluting an
// otherwise quiet stream. This lock makes sure suppressDisconnects() will
// block until we've either gotten our status update or disconnected from
// the device.
std::lock_guard<std::mutex> lk(heartbeatMutex);
if(heartbeatSuppressed())
continue;
// No heartbeat received, request a status // No heartbeat received, request a status
com->sendCommand(Command::RequestStatusUpdate); com->sendCommand(Command::RequestStatusUpdate);
// The response should come back quickly if the com is quiet // The response should come back quickly if the com is quiet
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
// Check if we got a message, and if not, if settings are being applied // Check if we got a message, and if not, if settings are being applied
if(!receivedMessage && !heartbeatSuppressed()) { if(receivedMessage) {
receivedMessage = false;
} else {
if(!stopHeartbeatThread && !isDisconnected()) if(!stopHeartbeatThread && !isDisconnected())
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error); report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
break; break;
} }
} }
receivedMessage = false;
} }
com->removeMessageCallback(messageReceivedCallbackID); com->removeMessageCallback(messageReceivedCallbackID);
@ -333,8 +347,8 @@ bool Device::goOnline() {
updateLEDState(); updateLEDState();
MessageFilter filter(Network::NetID::Reset_Status); std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::Reset_Status);
filter.includeInternalInAny = true; filter->includeInternalInAny = true;
// Wait until communication is enabled or 5 seconds, whichever comes first // Wait until communication is enabled or 5 seconds, whichever comes first
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) { while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
@ -376,8 +390,8 @@ bool Device::goOffline() {
updateLEDState(); updateLEDState();
MessageFilter filter(Network::NetID::Reset_Status); std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Network::NetID::Reset_Status);
filter.includeInternalInAny = true; filter->includeInternalInAny = true;
// Wait until communication is disabled or 5 seconds, whichever comes first // Wait until communication is disabled or 5 seconds, whichever comes first
while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) { while((std::chrono::system_clock::now() - startTime) < std::chrono::seconds(5)) {
@ -395,20 +409,18 @@ bool Device::goOffline() {
return true; return true;
} }
bool Device::transmit(std::shared_ptr<Message> message) { bool Device::transmit(std::shared_ptr<Frame> frame) {
// not open
if(!isOpen()) { if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return false; return false;
} }
// not online
if(!isOnline()) { if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error); report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return false; return false;
} }
if(!isSupportedTXNetwork(message->network)) { if(!isSupportedTXNetwork(frame->network)) {
report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error); report(APIEvent::Type::UnsupportedTXNetwork, APIEvent::Severity::Error);
return false; return false;
} }
@ -416,7 +428,7 @@ bool Device::transmit(std::shared_ptr<Message> message) {
bool extensionHookedTransmit = false; bool extensionHookedTransmit = false;
bool transmitStatusFromExtension = false; bool transmitStatusFromExtension = false;
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
if(!ext->transmitHook(message, transmitStatusFromExtension)) if(!ext->transmitHook(frame, transmitStatusFromExtension))
extensionHookedTransmit = true; extensionHookedTransmit = true;
return !extensionHookedTransmit; // false breaks out of the loop early return !extensionHookedTransmit; // false breaks out of the loop early
}); });
@ -424,15 +436,15 @@ bool Device::transmit(std::shared_ptr<Message> message) {
return transmitStatusFromExtension; return transmitStatusFromExtension;
std::vector<uint8_t> packet; std::vector<uint8_t> packet;
if(!com->encoder->encode(*com->packetizer, packet, message)) if(!com->encoder->encode(*com->packetizer, packet, frame))
return false; return false;
return com->sendPacket(packet); return com->sendPacket(packet);
} }
bool Device::transmit(std::vector<std::shared_ptr<Message>> messages) { bool Device::transmit(std::vector<std::shared_ptr<Frame>> frames) {
for(auto& message : messages) { for(auto& frame : frames) {
if(!transmit(message)) if(!transmit(frame))
return false; return false;
} }
return true; return true;
@ -463,6 +475,108 @@ Network Device::getNetworkByNumber(Network::Type type, size_t index) const {
return Network::NetID::Invalid; return Network::NetID::Invalid;
} }
optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
if(!into || timeout <= std::chrono::milliseconds(0)) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullopt;
}
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
std::lock_guard<std::mutex> lk(diskLock);
if(diskReadDriver->getAccess() == Disk::Access::EntireCard && diskWriteDriver->getAccess() == Disk::Access::VSA) {
// We have mismatched drivers, we need to add an offset to the diskReadDriver
const auto offset = Disk::FindVSAInFAT([this, &timeout](uint64_t pos, uint8_t *into, uint64_t amount) {
const auto start = std::chrono::steady_clock::now();
auto ret = diskReadDriver->readLogicalDisk(*com, report, pos, into, amount, timeout);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
return ret;
});
if(!offset.has_value())
return nullopt;
diskReadDriver->setVSAOffset(*offset);
}
// This is needed for certain read drivers which take over the communication stream
const auto lifetime = suppressDisconnects();
return diskReadDriver->readLogicalDisk(*com, report, pos, into, amount, timeout);
}
optional<uint64_t> Device::writeLogicalDisk(uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) {
if(!from || timeout <= std::chrono::milliseconds(0)) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return nullopt;
}
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
std::lock_guard<std::mutex> lk(diskLock);
return diskWriteDriver->writeLogicalDisk(*com, report, *diskReadDriver, pos, from, amount, timeout);
}
optional<bool> Device::isLogicalDiskConnected() {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
const auto info = com->getLogicalDiskInfoSync();
if (!info) {
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
return nullopt;
}
return info->connected;
}
optional<uint64_t> Device::getLogicalDiskSize() {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
const auto info = com->getLogicalDiskInfoSync();
if (!info) {
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
return nullopt;
}
return info->getReportedSize();
}
optional<uint64_t> Device::getVSAOffsetInLogicalDisk() {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
std::lock_guard<std::mutex> lk(diskLock);
if (diskReadDriver->getAccess() == Disk::Access::VSA || diskReadDriver->getAccess() == Disk::Access::None)
return 0ull;
auto offset = Disk::FindVSAInFAT([this](uint64_t pos, uint8_t *into, uint64_t amount) {
return diskReadDriver->readLogicalDisk(*com, report, pos, into, amount);
});
if(!offset.has_value())
return nullopt;
if(diskReadDriver->getAccess() == Disk::Access::EntireCard && diskWriteDriver->getAccess() == Disk::Access::VSA) {
// We have mismatched drivers, we need to add an offset to the diskReadDriver
diskReadDriver->setVSAOffset(*offset);
return 0ull;
}
return *offset;
}
optional<bool> Device::getDigitalIO(IO type, size_t number /* = 1 */) { optional<bool> Device::getDigitalIO(IO type, size_t number /* = 1 */) {
if(number == 0) { // Start counting from 1 if(number == 0) { // Start counting from 1
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error); report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
@ -668,8 +782,9 @@ optional<double> Device::getAnalogIO(IO type, size_t number /* = 1 */) {
} }
Lifetime Device::suppressDisconnects() { Lifetime Device::suppressDisconnects() {
std::lock_guard<std::mutex> lk(heartbeatMutex);
heartbeatSuppressedByUser++; heartbeatSuppressedByUser++;
return Lifetime([this] { heartbeatSuppressedByUser--; }); return Lifetime([this] { std::lock_guard<std::mutex> lk2(heartbeatMutex); heartbeatSuppressedByUser--; });
} }
void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) { void Device::addExtension(std::shared_ptr<DeviceExtension>&& extension) {
@ -692,11 +807,17 @@ void Device::forEachExtension(std::function<bool(const std::shared_ptr<DeviceExt
} }
void Device::handleInternalMessage(std::shared_ptr<Message> message) { void Device::handleInternalMessage(std::shared_ptr<Message> message) {
switch(message->network.getNetID()) { switch(message->type) {
case Network::NetID::Reset_Status: case Message::Type::ResetStatus:
latestResetStatus = std::dynamic_pointer_cast<ResetStatusMessage>(message); latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message);
break; break;
case Message::Type::RawMessage: {
auto rawMessage = std::static_pointer_cast<RawMessage>(message);
switch(rawMessage->network.getNetID()) {
case Network::NetID::Device: { case Network::NetID::Device: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message); auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg) if(canmsg)
handleNeoVIMessage(std::move(canmsg)); handleNeoVIMessage(std::move(canmsg));
@ -704,11 +825,15 @@ void Device::handleInternalMessage(std::shared_ptr<Message> message) {
} }
case Network::NetID::DeviceStatus: case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves // Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(message); handleDeviceStatus(rawMessage);
break; break;
default: default:
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl; break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
} }
break;
}
default: break;
}
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
ext->handleMessage(message); ext->handleMessage(message);
return true; // false breaks out early return true; // false breaks out early
@ -766,3 +891,34 @@ void Device::updateLEDState() {
std::vector<uint8_t> args {(uint8_t) ledState}; std::vector<uint8_t> args {(uint8_t) ledState};
com->sendCommand(Command::UpdateLEDState, args); com->sendCommand(Command::UpdateLEDState, args);
} }
optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
if(!getEthPhyRegControlSupported()) {
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
return nullopt;
}
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return nullopt;
}
std::vector<uint8_t> bytes;
HardwareEthernetPhyRegisterPacket::EncodeFromMessage(message, bytes, report);
std::shared_ptr<Message> response = com->waitForMessageSync(
[this, bytes](){ return com->sendCommand(Command::PHYControlRegisters, bytes); },
std::make_shared<MessageFilter>(Network::NetID::EthPHYControl), timeout);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return nullopt;
}
auto retMsg = std::static_pointer_cast<EthPhyMessage>(response);
if(!retMsg) {
return nullopt;
}
return make_optional<EthPhyMessage>(*retMsg);
}

View File

@ -1,10 +1,173 @@
#include "icsneo/device/devicefinder.h" #include "icsneo/device/devicefinder.h"
#include "icsneo/platform/devices.h" #include "icsneo/platform/devices.h"
#include "icsneo/device/founddevice.h"
#include "generated/extensions/builtin.h" #include "generated/extensions/builtin.h"
#ifdef ICSNEO_ENABLE_FIRMIO
#include "icsneo/platform/firmio.h"
#endif
#ifdef ICSNEO_ENABLE_RAW_ETHERNET
#include "icsneo/platform/pcap.h"
#endif
#ifdef ICSNEO_ENABLE_CDCACM
#include "icsneo/platform/cdcacm.h"
#endif
#ifdef ICSNEO_ENABLE_FTDI
#include "icsneo/platform/ftdi.h"
#endif
using namespace icsneo; using namespace icsneo;
static bool supportedDevicesCached = false; template<typename T>
static void makeIfSerialMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
// Relies on the subclass to have a `static constexpr const char* SERIAL_START = "XX"`
// and also a public constructor `T(const FoundDevice& dev)`
// Use macro ICSNEO_FINDABLE_DEVICE() to create these
if(dev.serial[0] == T::SERIAL_START[0] && dev.serial[1] == T::SERIAL_START[1])
into.push_back(std::make_shared<T>(dev));
}
template<typename T>
static void makeIfPIDMatches(const FoundDevice& dev, std::vector<std::shared_ptr<Device>>& into) {
// Relies on the subclass to have a `static constexpr uint16_t PRODUCT_ID = 0x1111`
// and also a public constructor `T(const FoundDevice& dev)`
// Use macro ICSNEO_FINDABLE_DEVICE_BY_PID() to create these
if(dev.productId == T::PRODUCT_ID)
into.push_back(std::make_shared<T>(dev));
}
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
static std::vector<FoundDevice> driverFoundDevices;
driverFoundDevices.clear();
#ifdef ICSNEO_ENABLE_FIRMIO
FirmIO::Find(driverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_RAW_ETHERNET
PCAP::Find(driverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_CDCACM
CDCACM::Find(driverFoundDevices);
#endif
#ifdef ICSNEO_ENABLE_FTDI
FTDI::Find(driverFoundDevices);
#endif
std::vector<std::shared_ptr<Device>> foundDevices;
// Offer found devices to each of the subclasses
for (const FoundDevice& dev : driverFoundDevices) {
#ifdef __ETHERBADGE_H_
makeIfSerialMatches<EtherBADGE>(dev, foundDevices);
#endif
#ifdef __NEOOBD2PRO_H_
makeIfSerialMatches<NeoOBD2PRO>(dev, foundDevices);
#endif
#ifdef __NEOOBD2SIM_H_
makeIfSerialMatches<NeoOBD2SIM>(dev, foundDevices);
#endif
#ifdef __NEOVIFIRE_H_
makeIfPIDMatches<NeoVIFIRE>(dev, foundDevices);
#endif
#ifdef __NEOVIFIRE2_H_
makeIfSerialMatches<NeoVIFIRE2>(dev, foundDevices);
#endif
#ifdef __NEOVIRED2_H_
makeIfSerialMatches<NeoVIRED2>(dev, foundDevices);
#endif
#ifdef __NEOVIION_H_
makeIfPIDMatches<NeoVIION>(dev, foundDevices);
#endif
#ifdef __NEOVIPLASMA_H_
makeIfPIDMatches<NeoVIPLASMA>(dev, foundDevices);
#endif
#ifdef __RADEPSILON_H_
makeIfSerialMatches<RADEpsilon>(dev, foundDevices);
#endif
#ifdef __RADGALAXY_H_
makeIfSerialMatches<RADGalaxy>(dev, foundDevices);
#endif
#ifdef __RADMARS_H_
makeIfSerialMatches<RADMars>(dev, foundDevices);
#endif
#ifdef __RADGIGASTAR_H_
makeIfSerialMatches<RADGigastar>(dev, foundDevices);
#endif
#ifdef __RADMOON2_H_
makeIfSerialMatches<RADMoon2>(dev, foundDevices);
#endif
#ifdef __RADMOONDUO_H_
makeIfSerialMatches<RADMoonDuo>(dev, foundDevices);
#endif
#ifdef __RADPLUTO_H_
makeIfSerialMatches<RADPluto>(dev, foundDevices);
#endif
#ifdef __RADSTAR2_H_
makeIfSerialMatches<RADStar2>(dev, foundDevices);
#endif
#ifdef __RADSUPERMOON_H_
makeIfSerialMatches<RADSupermoon>(dev, foundDevices);
#endif
#ifdef __VALUECAN3_H_
makeIfPIDMatches<ValueCAN3>(dev, foundDevices);
#endif
#ifdef __VALUECAN4_1_H_
makeIfSerialMatches<ValueCAN4_1>(dev, foundDevices);
#endif
#ifdef __VALUECAN4_2_H_
makeIfSerialMatches<ValueCAN4_2>(dev, foundDevices);
#endif
#ifdef __VALUECAN4_2EL_H_
makeIfSerialMatches<ValueCAN4_2EL>(dev, foundDevices);
#endif
#ifdef __VALUECAN4_4_H_
makeIfSerialMatches<ValueCAN4_4>(dev, foundDevices);
#endif
#ifdef __VALUECAN4INDUSTRIAL_H_
makeIfSerialMatches<ValueCAN4Industrial>(dev, foundDevices);
#endif
#ifdef __VIVIDCAN_H_
makeIfSerialMatches<VividCAN>(dev, foundDevices);
#endif
}
for(auto& device : foundDevices) {
AddBuiltInExtensionsTo(device);
}
return foundDevices;
}
const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
static std::vector<DeviceType> supportedDevices = { static std::vector<DeviceType> supportedDevices = {
#ifdef __ETHERBADGE_H_ #ifdef __ETHERBADGE_H_
@ -27,12 +190,8 @@ static std::vector<DeviceType> supportedDevices = {
NeoVIFIRE::DEVICE_TYPE, NeoVIFIRE::DEVICE_TYPE,
#endif #endif
#ifdef __NEOVIFIRE2ETH_H_ #ifdef __NEOVIFIRE2_H_
NeoVIFIRE2ETH::DEVICE_TYPE, NeoVIFIRE2::DEVICE_TYPE,
#endif
#ifdef __NEOVIFIRE2USB_H_
NeoVIFIRE2USB::DEVICE_TYPE,
#endif #endif
#ifdef __NEOVIION_H_ #ifdef __NEOVIION_H_
@ -51,20 +210,12 @@ static std::vector<DeviceType> supportedDevices = {
RADGalaxy::DEVICE_TYPE, RADGalaxy::DEVICE_TYPE,
#endif #endif
#ifdef __RADGIGALOG_ETH_H_ #ifdef __RADMARS_H_
RADGigalogETH::DEVICE_TYPE, RADMars::DEVICE_TYPE,
#endif #endif
#ifdef __RADGIGALOG_USB_H_ #ifdef __RADGIGASTAR_H_
RADGigalogUSB::DEVICE_TYPE, RADGigastar::DEVICE_TYPE,
#endif
#ifdef __RADGIGASTAR_ETH_H_
RADGigastarETH::DEVICE_TYPE,
#endif
#ifdef __RADGIGASTAR_USB_H_
RADGigastarUSB::DEVICE_TYPE,
#endif #endif
#ifdef __RADMOON2_H_ #ifdef __RADMOON2_H_
@ -75,16 +226,12 @@ static std::vector<DeviceType> supportedDevices = {
RADMoonDuo::DEVICE_TYPE, RADMoonDuo::DEVICE_TYPE,
#endif #endif
#ifdef __RADPLUTOUSB_H_ #ifdef __RADPLUTO_H_
RADPlutoUSB::DEVICE_TYPE, RADPluto::DEVICE_TYPE,
#endif #endif
#ifdef __RADSTAR2ETH_H_ #ifdef __RADSTAR2_H_
RADStar2ETH::DEVICE_TYPE, RADStar2::DEVICE_TYPE,
#endif
#ifdef __RADSTAR2USB_H_
RADStar2USB::DEVICE_TYPE,
#endif #endif
#ifdef __RADSUPERMOON_H_ #ifdef __RADSUPERMOON_H_
@ -103,24 +250,16 @@ static std::vector<DeviceType> supportedDevices = {
ValueCAN4_2::DEVICE_TYPE, ValueCAN4_2::DEVICE_TYPE,
#endif #endif
#ifdef __VALUECAN4_2EL_ETH_H_ #ifdef __VALUECAN4_2EL_H_
ValueCAN4_2EL_ETH::DEVICE_TYPE, ValueCAN4_2EL::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4_2EL_USB_H_
ValueCAN4_2EL_USB::DEVICE_TYPE,
#endif #endif
#ifdef __VALUECAN4_4_H_ #ifdef __VALUECAN4_4_H_
ValueCAN4_4::DEVICE_TYPE, ValueCAN4_4::DEVICE_TYPE,
#endif #endif
#ifdef __VALUECAN4INDUSTRIAL_ETH_H_ #ifdef __VALUECAN4INDUSTRIAL_H_
ValueCAN4IndustrialETH::DEVICE_TYPE, ValueCAN4Industrial::DEVICE_TYPE,
#endif
#ifdef __VALUECAN4INDUSTRIAL_USB_H_
ValueCAN4IndustrialUSB::DEVICE_TYPE,
#endif #endif
#ifdef __VIVIDCAN_H_ #ifdef __VIVIDCAN_H_
@ -129,150 +268,5 @@ static std::vector<DeviceType> supportedDevices = {
}; };
std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
std::vector<std::shared_ptr<Device>> foundDevices;
std::vector<std::vector<std::shared_ptr<Device>>> findResults;
#if defined(LIBICSNEO_HAVE_PCAP) && LIBICSNEO_HAVE_PCAP == 1
auto pcapDevices = PCAP::FindAll();
#endif
#ifdef __ETHERBADGE_H_
findResults.push_back(EtherBADGE::Find());
#endif
#ifdef __NEOOBD2PRO_H_
findResults.push_back(NeoOBD2PRO::Find());
#endif
#ifdef __NEOOBD2SIM_H_
findResults.push_back(NeoOBD2SIM::Find());
#endif
#ifdef __NEOVIFIRE_H_
findResults.push_back(NeoVIFIRE::Find());
#endif
#ifdef __NEOVIFIRE2ETH_H_
findResults.push_back(NeoVIFIRE2ETH::Find(pcapDevices));
#endif
#ifdef __NEOVIFIRE2USB_H_
findResults.push_back(NeoVIFIRE2USB::Find());
#endif
#ifdef __NEOVIRED2_H_
findResults.push_back(NeoVIRED2::Find(pcapDevices));
#endif
#ifdef __NEOVIION_H_
findResults.push_back(NeoVIION::Find());
#endif
#ifdef __NEOVIPLASMA_H_
findResults.push_back(NeoVIPLASMA::Find());
#endif
#ifdef __RADEPSILON_H_
findResults.push_back(RADEpsilon::Find());
#endif
#ifdef __RADGALAXY_H_
findResults.push_back(RADGalaxy::Find(pcapDevices));
#endif
#ifdef __RADGIGALOG_ETH_H_
findResults.push_back(RADGigalogETH::Find(pcapDevices));
#endif
#ifdef __RADGIGALOG_USB_H_
findResults.push_back(RADGigalogUSB::Find());
#endif
#ifdef __RADGIGASTAR_ETH_H_
findResults.push_back(RADGigastarETH::Find(pcapDevices));
#endif
#ifdef __RADGIGASTAR_USB_H_
findResults.push_back(RADGigastarUSB::Find());
#endif
#ifdef __RADMOON2_H_
findResults.push_back(RADMoon2::Find());
#endif
#ifdef __RADMOONDUO_H_
findResults.push_back(RADMoonDuo::Find());
#endif
#ifdef __RADPLUTOUSB_H_
findResults.push_back(RADPlutoUSB::Find());
#endif
#ifdef __RADSTAR2ETH_H_
findResults.push_back(RADStar2ETH::Find(pcapDevices));
#endif
#ifdef __RADSTAR2USB_H_
findResults.push_back(RADStar2USB::Find());
#endif
#ifdef __RADSUPERMOON_H_
findResults.push_back(RADSupermoon::Find());
#endif
#ifdef __VALUECAN3_H_
findResults.push_back(ValueCAN3::Find());
#endif
#ifdef __VALUECAN4_1_H_
findResults.push_back(ValueCAN4_1::Find());
#endif
#ifdef __VALUECAN4_2_H_
findResults.push_back(ValueCAN4_2::Find());
#endif
#ifdef __VALUECAN4_2EL_ETH_H_
findResults.push_back(ValueCAN4_2EL_ETH::Find(pcapDevices));
#endif
#ifdef __VALUECAN4_2EL_USB_H_
findResults.push_back(ValueCAN4_2EL_USB::Find());
#endif
#ifdef __VALUECAN4_4_H_
findResults.push_back(ValueCAN4_4::Find());
#endif
#ifdef __VALUECAN4INDUSTRIAL_ETH_H_
findResults.push_back(ValueCAN4IndustrialETH::Find(pcapDevices));
#endif
#ifdef __VALUECAN4INDUSTRIAL_USB_H_
findResults.push_back(ValueCAN4IndustrialUSB::Find());
#endif
#ifdef __VIVIDCAN_H_
findResults.push_back(VividCAN::Find());
#endif
for(auto& results : findResults) {
if(results.size())
foundDevices.insert(foundDevices.end(), std::make_move_iterator(results.begin()), std::make_move_iterator(results.end()));
}
for(auto& device : foundDevices) {
AddBuiltInExtensionsTo(device);
}
return foundDevices;
}
const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
if(!supportedDevicesCached) {
supportedDevices.erase(std::unique(supportedDevices.begin(), supportedDevices.end()), supportedDevices.end());
supportedDevicesCached = true;
}
return supportedDevices; return supportedDevices;
} }

View File

@ -202,7 +202,7 @@ bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
first->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2; first->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
first->baseCycle = 0; first->baseCycle = 0;
first->cycleRepetition = 1; first->cycleRepetition = 1;
first->continuousMode = true; first->continuousMode = false;
staticTx.push_back(first); staticTx.push_back(first);
firstUsed = true; firstUsed = true;
@ -215,7 +215,7 @@ bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
second->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2; second->frameLengthBytes = clusterConfig.PayloadLengthOfStaticSlotInWords * 2;
second->baseCycle = 0; second->baseCycle = 0;
second->cycleRepetition = 1; second->cycleRepetition = 1;
second->continuousMode = true; second->continuousMode = false;
staticTx.push_back(second); staticTx.push_back(second);
secondUsed = true; secondUsed = true;
} }
@ -225,7 +225,7 @@ bool FlexRay::Controller::configure(std::chrono::milliseconds timeout) {
if(!buf->isTransmit) if(!buf->isTransmit)
continue; // Only transmit frames need to be written to the controller continue; // Only transmit frames need to be written to the controller
if(buf->frameID == controllerConfig.KeySlotID) { if((controllerConfig.KeySlotUsedForSync || controllerConfig.KeySlotOnlyEnabled) && buf->frameID == controllerConfig.KeySlotID) {
first = buf; first = buf;
staticTx[0] = buf; staticTx[0] = buf;
// Enforce keyslot rules // Enforce keyslot rules
@ -436,6 +436,10 @@ bool FlexRay::Controller::transmit(const std::shared_ptr<FlexRayMessage>& frmsg)
if(frmsg->channel != bufChannel) if(frmsg->channel != bufChannel)
continue; continue;
// If we have added changed our configuration, such as adding a message buffer, we will need to reconfigure
if(configDirty && lastSeenRunning)
start();
// This is a message buffer we want to fill // This is a message buffer we want to fill
if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteMessageBufferArgs(index, buf->_id, frmsg->data, buf->frameLengthBytes))) if(!device.com->sendCommand(Command::FlexRayControl, FlexRayControlMessage::BuildWriteMessageBufferArgs(index, buf->_id, frmsg->data, buf->frameLengthBytes)))
continue; continue;
@ -474,7 +478,20 @@ bool FlexRay::Controller::setCurrentPOCCommand(FlexRay::POCCommand cmd, bool che
const auto writeDuration = std::chrono::steady_clock::now() - beforeWrite; const auto writeDuration = std::chrono::steady_clock::now() - beforeWrite;
timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - writeDuration); timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout - writeDuration);
return wasCommandSuccessful(timeout); const bool success = wasCommandSuccessful(timeout);
if(success) {
switch(cmd) {
case FlexRay::POCCommand::Run:
lastSeenRunning = true;
break;
case FlexRay::POCCommand::Halt:
case FlexRay::POCCommand::Freeze:
lastSeenRunning = false;
break;
default: break;
}
}
return success;
} }
bool FlexRay::Controller::wasCommandSuccessful(std::chrono::milliseconds timeout) const { bool FlexRay::Controller::wasCommandSuccessful(std::chrono::milliseconds timeout) const {
@ -593,6 +610,7 @@ uint16_t FlexRay::Controller::CalculateCycleFilter(uint8_t baseCycle, uint8_t cy
} }
std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, std::chrono::milliseconds timeout) const { std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, std::chrono::milliseconds timeout) const {
static const std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(icsneo::Network::NetID::FlexRayControl);
if(timeout.count() <= 20) if(timeout.count() <= 20)
return {false, 0}; // Out of time! return {false, 0}; // Out of time!
@ -611,7 +629,7 @@ std::pair<bool, uint32_t> FlexRay::Controller::readRegister(ERAYRegister reg, st
return false; // Command failed to send return false; // Command failed to send
lastSent = std::chrono::steady_clock::now(); lastSent = std::chrono::steady_clock::now();
return true; return true;
}, MessageFilter(icsneo::Network::NetID::FlexRayControl), timeout); }, filter, timeout);
if(auto frmsg = std::dynamic_pointer_cast<FlexRayControlMessage>(msg)) { if(auto frmsg = std::dynamic_pointer_cast<FlexRayControlMessage>(msg)) {
if(frmsg->decoded && frmsg->controller == index && frmsg->opcode == FlexRay::Opcode::ReadCCRegs) if(frmsg->decoded && frmsg->controller == index && frmsg->opcode == FlexRay::Opcode::ReadCCRegs)
resp = frmsg; resp = frmsg;

View File

@ -26,18 +26,16 @@ void FlexRay::Extension::onGoOffline() {
} }
void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) { void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message) {
switch(message->network.getNetID()) { switch(message->type) {
case Network::NetID::FlexRayControl: { case Message::Type::FlexRayControl: {
auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message); auto msg = std::dynamic_pointer_cast<FlexRayControlMessage>(message);
if(!msg || !msg->decoded) if(!msg || !msg->decoded)
return; return;
switch(msg->opcode) { switch(msg->opcode) {
case FlexRay::Opcode::ReadCCStatus: case FlexRay::Opcode::ReadCCStatus:
if(auto status = std::dynamic_pointer_cast<FlexRayControlMessage>(message)) { // TODO else report error? if(msg->controller >= controllers.size())
if(status->controller >= controllers.size())
return; // TODO error return; // TODO error
controllers[status->controller]->_setStatus(status); controllers[msg->controller]->_setStatus(msg);
}
break; break;
} }
break; break;
@ -47,18 +45,18 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
} }
} }
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Message>& message, bool& success) { bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) {
if(!message || message->network.getType() != Network::Type::FlexRay) if(!frame || frame->network.getType() != Network::Type::FlexRay)
return true; // Don't hook non-FlexRay messages return true; // Don't hook non-FlexRay messages
success = false; success = false;
std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(message); std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(frame);
if(!frmsg) if(!frmsg)
return false; return false;
for(auto& controller : controllers) { for(auto& controller : controllers) {
if(controller->getNetwork() != message->network) if(controller->getNetwork() != frame->network)
continue; continue;
success |= controller->transmit(frmsg); success |= controller->transmit(frmsg);
} }

View File

@ -228,9 +228,9 @@ bool IDeviceSettings::apply(bool temporary) {
// Pause I/O with the device while the settings are applied // Pause I/O with the device while the settings are applied
applyingSettings = true; applyingSettings = true;
std::shared_ptr<Message> msg = com->waitForMessageSync([this, &bytestream]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { // We did not receive a response if(!msg || msg->data[0] != 1) { // We did not receive a response
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
@ -254,9 +254,9 @@ bool IDeviceSettings::apply(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@ -267,9 +267,9 @@ bool IDeviceSettings::apply(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return com->sendCommand(Command::SaveSettings);
}, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000)); }, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; applyingSettings = false;
@ -296,9 +296,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
applyingSettings = true; applyingSettings = true;
std::shared_ptr<Message> msg = com->waitForMessageSync([this]() { std::shared_ptr<Main51Message> msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SetDefaultSettings); return com->sendCommand(Command::SetDefaultSettings);
}, Main51MessageFilter(Command::SetDefaultSettings), std::chrono::milliseconds(1000)); }, std::make_shared<Main51MessageFilter>(Command::SetDefaultSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@ -331,9 +331,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
bytestream[6] = (uint8_t)(*gsChecksum >> 8); bytestream[6] = (uint8_t)(*gsChecksum >> 8);
memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size()); memcpy(bytestream.data() + 7, getMutableRawStructurePointer(), settings.size());
msg = com->waitForMessageSync([this, &bytestream]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this, &bytestream]() {
return com->sendCommand(Command::SetSettings, bytestream); return com->sendCommand(Command::SetSettings, bytestream);
}, Main51MessageFilter(Command::SetSettings), std::chrono::milliseconds(1000)); }, std::make_shared<Main51MessageFilter>(Command::SetSettings), std::chrono::milliseconds(1000)));
if(!msg || msg->data[0] != 1) { if(!msg || msg->data[0] != 1) {
// Attempt to get the settings from the device so we're up to date if possible // Attempt to get the settings from the device so we're up to date if possible
if(refresh()) { if(refresh()) {
@ -344,9 +344,9 @@ bool IDeviceSettings::applyDefaults(bool temporary) {
} }
if(!temporary) { if(!temporary) {
msg = com->waitForMessageSync([this]() { msg = std::dynamic_pointer_cast<Main51Message>(com->waitForMessageSync([this]() {
return com->sendCommand(Command::SaveSettings); return com->sendCommand(Command::SaveSettings);
}, Main51MessageFilter(Command::SaveSettings), std::chrono::milliseconds(5000)); }, std::make_shared<Main51MessageFilter>(Command::SaveSettings), std::chrono::milliseconds(5000)));
} }
applyingSettings = false; applyingSettings = false;

View File

@ -0,0 +1,13 @@
#include "icsneo/device/neodevice.h"
#include "icsneo/device/founddevice.h"
#include <cstring>
neodevice_t::neodevice_t() : device(nullptr), handle(0), type(0) {
memset(serial, 0, sizeof(serial));
}
neodevice_t::neodevice_t(const icsneo::FoundDevice& found, devicetype_t inType)
: device(nullptr), handle(found.handle), type(inType) {
static_assert(sizeof(found.serial) == sizeof(serial), "Serial sizes should match!");
memcpy(serial, found.serial, sizeof(serial));
}

View File

@ -0,0 +1,71 @@
#include "icsneo/disk/diskreaddriver.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
optional<uint64_t> ReadDriver::readLogicalDisk(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
if(amount == 0)
return 0;
optional<uint64_t> ret;
// Read into here if we can't read directly into the user buffer
// That would be the case either if we don't want some at the
// beginning or end of the block.
std::vector<uint8_t> alignedReadBuffer;
pos += vsaOffset;
const uint32_t idealBlockSize = getBlockSizeBounds().second;
const uint64_t startBlock = pos / idealBlockSize;
const uint32_t posWithinFirstBlock = static_cast<uint32_t>(pos % idealBlockSize);
uint64_t blocks = amount / idealBlockSize + (amount % idealBlockSize ? 1 : 0);
if(blocks * idealBlockSize - posWithinFirstBlock < amount)
blocks++; // We need one more block to get the last partial block's worth
uint64_t blocksProcessed = 0;
while(blocksProcessed < blocks && timeout >= std::chrono::milliseconds::zero()) {
const uint64_t currentBlock = startBlock + blocksProcessed;
uint64_t intoOffset = blocksProcessed * idealBlockSize;;
if(intoOffset < posWithinFirstBlock)
intoOffset = 0;
else
intoOffset -= posWithinFirstBlock;
const uint32_t posWithinCurrentBlock = (blocksProcessed ? 0 : posWithinFirstBlock);
uint32_t curAmt = idealBlockSize - posWithinCurrentBlock;
const auto amountLeft = amount - ret.value_or(0);
if(curAmt > amountLeft)
curAmt = static_cast<uint32_t>(amountLeft);
const bool useAlignedReadBuffer = (posWithinCurrentBlock != 0 || curAmt != idealBlockSize);
if(useAlignedReadBuffer && alignedReadBuffer.size() < idealBlockSize)
alignedReadBuffer.resize(idealBlockSize);
auto start = std::chrono::high_resolution_clock::now();
auto readAmount = readLogicalDiskAligned(com, report, currentBlock * idealBlockSize,
useAlignedReadBuffer ? alignedReadBuffer.data() : (into + intoOffset), idealBlockSize, timeout);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
if(!readAmount.has_value() || *readAmount < curAmt) {
if(timeout < std::chrono::milliseconds::zero())
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
else
report((blocksProcessed || readAmount.value_or(0u) != 0u) ? APIEvent::Type::EOFReached :
APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
break;
}
if(useAlignedReadBuffer)
memcpy(into + intoOffset, alignedReadBuffer.data() + posWithinCurrentBlock, curAmt);
if(!ret)
ret.emplace();
*ret += std::min<uint64_t>(*readAmount, curAmt);
blocksProcessed++;
}
return ret;
}

View File

@ -0,0 +1,97 @@
#include "icsneo/disk/diskwritedriver.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
const uint64_t WriteDriver::RetryAtomic = std::numeric_limits<uint64_t>::max();
const APIEvent::Severity WriteDriver::NonatomicSeverity = APIEvent::Severity::EventInfo;
optional<uint64_t> WriteDriver::writeLogicalDisk(Communication& com, device_eventhandler_t report, ReadDriver& readDriver,
uint64_t pos, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) {
if(amount == 0)
return 0;
optional<uint64_t> ret;
const uint32_t idealBlockSize = getBlockSizeBounds().second;
// Write from here if we need to read-modify-write a block
// That would be the case either if we don't want some at the
// beginning or end of the block.
std::vector<uint8_t> alignedWriteBuffer;
// Read to here, ideally this can be sent back to the device to
// ensure an operation is atomic
std::vector<uint8_t> atomicBuffer(idealBlockSize);
pos += vsaOffset;
const uint64_t startBlock = pos / idealBlockSize;
const uint32_t posWithinFirstBlock = static_cast<uint32_t>(pos % idealBlockSize);
uint64_t blocks = amount / idealBlockSize + (amount % idealBlockSize ? 1 : 0);
if(blocks * idealBlockSize - posWithinFirstBlock < amount)
blocks++; // We need one more block to get the last partial block's worth
uint64_t blocksProcessed = 0;
while(blocksProcessed < blocks && timeout >= std::chrono::milliseconds::zero()) {
const uint64_t currentBlock = startBlock + blocksProcessed;
uint64_t fromOffset = blocksProcessed * idealBlockSize;
if(fromOffset < posWithinFirstBlock)
fromOffset = 0;
else
fromOffset -= posWithinFirstBlock;
const uint32_t posWithinCurrentBlock = (blocksProcessed ? 0 : posWithinFirstBlock);
uint32_t curAmt = idealBlockSize - posWithinCurrentBlock;
const auto amountLeft = amount - ret.value_or(0);
if(curAmt > amountLeft)
curAmt = static_cast<uint32_t>(amountLeft);
auto start = std::chrono::high_resolution_clock::now();
const auto reportFromRead = [&report, &blocksProcessed](APIEvent::Type t, APIEvent::Severity s) {
if(t == APIEvent::Type::ParameterOutOfRange && blocksProcessed)
t = APIEvent::Type::EOFReached;
report(t, s);
};
auto bytesTransferred = readDriver.readLogicalDisk(com, reportFromRead, currentBlock * idealBlockSize,
atomicBuffer.data(), idealBlockSize, timeout);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
if(bytesTransferred != idealBlockSize)
break; // readLogicalDisk reports its own errors
const bool useAlignedWriteBuffer = (posWithinCurrentBlock != 0 || curAmt != idealBlockSize);
if(useAlignedWriteBuffer) {
alignedWriteBuffer = atomicBuffer;
memcpy(alignedWriteBuffer.data() + posWithinCurrentBlock, from + fromOffset, curAmt);
}
start = std::chrono::high_resolution_clock::now();
bytesTransferred = writeLogicalDiskAligned(com, report, currentBlock * idealBlockSize, atomicBuffer.data(),
useAlignedWriteBuffer ? alignedWriteBuffer.data() : (from + fromOffset), idealBlockSize, timeout);
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
if(bytesTransferred == RetryAtomic) {
// The user may want to log these events in order to see how many atomic misses they are getting
report(APIEvent::Type::AtomicOperationRetried, APIEvent::Severity::EventInfo);
continue;
}
if(!bytesTransferred.has_value() || *bytesTransferred < curAmt) {
if(timeout < std::chrono::milliseconds::zero())
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
else
report((blocksProcessed || bytesTransferred.value_or(0u) != 0u) ? APIEvent::Type::EOFReached :
APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
break;
}
if(!ret)
ret.emplace();
*ret += std::min<uint64_t>(*bytesTransferred, curAmt);
blocksProcessed++;
}
return ret;
}

View File

@ -0,0 +1,213 @@
#include "icsneo/disk/extextractordiskreaddriver.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/multichannelcommunication.h"
#include "icsneo/api/lifetime.h"
#include <cstring>
//#define ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
#include <iostream>
#endif
using namespace icsneo;
using namespace icsneo::Disk;
optional<uint64_t> ExtExtractorDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
if(amount > getBlockSizeBounds().second)
return nullopt;
if(amount % getBlockSizeBounds().first != 0)
return nullopt;
if(pos % getBlockSizeBounds().first != 0)
return nullopt;
optional<uint64_t> ret;
while(timeout > std::chrono::milliseconds(0) && !ret.has_value()) {
auto start = std::chrono::steady_clock::now();
ret = attemptReadLogicalDiskAligned(com, report, pos, into, amount, std::chrono::milliseconds(100));
timeout -= std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
}
return ret;
}
optional<uint64_t> ExtExtractorDiskReadDriver::attemptReadLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) {
uint64_t sector = pos / SectorSize;
uint64_t largeSectorCount = amount / SectorSize;
uint32_t sectorCount = uint32_t(largeSectorCount);
if (largeSectorCount != uint64_t(sectorCount))
return nullopt;
// The cache does not have this data, go get it
std::mutex m;
std::condition_variable cv;
uint16_t receiving = 0; // How much are we about to get before another header or completion
uint64_t received = 0;
uint16_t receivedCurrent = 0;
size_t skipping = 0;
std::vector<uint8_t> header;
std::unique_lock<std::mutex> lk(m);
bool error = !com.redirectRead([&](std::vector<uint8_t>&& data) {
std::unique_lock<std::mutex> lk2(m);
if(error) {
lk2.unlock();
cv.notify_all();
return;
}
if(skipping > data.size()) {
skipping -= data.size();
return;
}
size_t offset = skipping;
skipping = 0;
while(offset < data.size()) {
size_t left = data.size() - offset;
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Going to process " << left << " bytes" << std::endl;
#endif
if(header.size() != HeaderLength) {
if(header.empty() && left && data[offset] != 0xaa) {
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Incorrect header " << int(data[offset]) << ' ' << int(offset) << std::endl;
#endif
error = true;
lk2.unlock();
cv.notify_all();
return;
}
// Did we get a correct header and at least one byte of data?
const auto begin = data.begin() + offset;
int32_t headerLeft = int32_t(HeaderLength - header.size());
if(int32_t(left) < headerLeft) {
// Not enough data here, grab what header we can and continue
header.insert(header.end(), begin, data.end());
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Got " << int(left) << " bytes of header at " << offset << " (incomplete " <<
header.size() << ')' << std::endl;
#endif
return;
}
header.insert(header.end(), begin, begin + headerLeft);
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Got " << int(headerLeft) << " bytes of header at " << offset << " (complete " <<
header.size() << ')' << std::endl;
#endif
offset += headerLeft;
if(header[1] == uint8_t(Network::NetID::RED)) {
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Got extended response " << int(offset) << std::endl;
#endif
// This is the extended command response, not all devices send this
// If we got it, we need to figure out how much more data to ignore
uint16_t length = (header[2] + (header[3] << 8));
// Try for another header after this, regardless how much we choose
// to skip and how we skip it
header.clear();
if(length <= 6) {
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Incorrect extended response length " << int(length) << ' ' << int(offset) << std::endl;
#endif
error = true;
lk2.unlock();
cv.notify_all();
return;
}
length -= 7;
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Skipping " << int(length) << ' ' << int(left) << std::endl;
#endif
if(left < length) {
skipping = length - left;
return;
}
offset += length;
continue;
}
// The device tells us how much it's sending us before the next header
receiving = (header[5] | (header[6] << 8));
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Started packet of size " << receiving << " bytes" << std::endl;
#endif
}
left = data.size() - offset;
auto count = uint16_t(std::min<uint64_t>(std::min<uint64_t>(receiving - receivedCurrent, left), amount - received));
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "With " << int(left) << " bytes " << int(offset) << std::endl;
#endif
memcpy(cache.data() + received, data.data() + offset, count);
received += count;
receivedCurrent += count;
offset += count;
if(amount == received) {
if(receivedCurrent % 2 == 0)
offset++;
header.clear(); // Now we will need another header
lk2.unlock();
cv.notify_all();
lk2.lock();
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Finished!" << std::endl;
#endif
}
else if(receivedCurrent == receiving) {
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Got " << count << " bytes, " << receivedCurrent << " byte packet " << received <<
" complete of " << amount << std::endl;
#endif
if(receivedCurrent % 2 == 0)
offset++;
header.clear(); // Now we will need another header
receivedCurrent = 0;
} else {
#ifdef ICSNEO_EXTENDED_EXTRACTOR_DEBUG_PRINTS
std::cout << "Got " << count << " bytes, incomplete (of " << receiving << " bytes)" << std::endl;
#endif
}
}
});
Lifetime clearRedirect([&com, &lk] { lk.unlock(); com.clearRedirectRead(); });
if(error)
return nullopt;
error = !com.sendCommand(ExtendedCommand::Extract, {
uint8_t(sector & 0xff),
uint8_t((sector >> 8) & 0xff),
uint8_t((sector >> 16) & 0xff),
uint8_t((sector >> 24) & 0xff),
uint8_t((sector >> 32) & 0xff),
uint8_t((sector >> 40) & 0xff),
uint8_t((sector >> 48) & 0xff),
uint8_t((sector >> 56) & 0xff),
uint8_t(sectorCount & 0xff),
uint8_t((sectorCount >> 8) & 0xff),
uint8_t((sectorCount >> 16) & 0xff),
uint8_t((sectorCount >> 24) & 0xff),
});
if(error)
return nullopt;
bool hitTimeout = !cv.wait_for(lk, timeout, [&]() { return error || amount == received; });
if(hitTimeout || error)
return nullopt;
cachedAt = std::chrono::steady_clock::now();
cachePos = pos;
}
memcpy(into, cache.data(), size_t(amount));
return amount;
}

48
disk/fat.cpp 100644
View File

@ -0,0 +1,48 @@
#include "icsneo/disk/fat.h"
#include "icsneo/disk/diskdriver.h"
#include "ff.h"
#include "diskio.h"
#include <mutex>
using namespace icsneo;
// The FAT driver can only be accessed by one caller at a time, since it relies on globals
static std::mutex fatDriverMutex;
static std::function< optional<uint64_t>(uint64_t pos, uint8_t* into, uint64_t amount) > diskReadFn;
extern "C" DRESULT disk_read(BYTE, BYTE* buff, LBA_t sector, UINT count) {
static_assert(Disk::SectorSize == 512, "FatFs expects 512 byte sectors");
const uint64_t expected = count * uint64_t(Disk::SectorSize);
const auto res = diskReadFn(sector * uint64_t(Disk::SectorSize), buff, expected);
if (!res.has_value())
return RES_NOTRDY;
return res == expected ? RES_OK : RES_ERROR;
}
extern "C" DSTATUS disk_initialize(BYTE) {
return RES_OK;
}
extern "C" DSTATUS disk_status(BYTE) {
return RES_OK;
}
static uint64_t ClusterToSector(const FATFS& fs, DWORD cluster) {
return fs.database + (LBA_t)fs.csize * (cluster - 2);
}
optional<uint64_t> Disk::FindVSAInFAT(std::function< optional<uint64_t>(uint64_t pos, uint8_t* into, uint64_t amount) > diskRead) {
std::lock_guard<std::mutex> lk(fatDriverMutex);
diskReadFn = diskRead;
FATFS fs = {};
if (f_mount(&fs, (const TCHAR*)_TEXT(""), 0) != FR_OK)
return nullopt;
FIL logData = {};
if (f_open(&logData, (const TCHAR*)_TEXT("0:\\LOG_DATA.VSA"), FA_READ) != FR_OK)
return nullopt;
return ClusterToSector(fs, logData.obj.sclust) * uint64_t(Disk::SectorSize);
}

View File

@ -0,0 +1,92 @@
#include "icsneo/disk/neomemorydiskdriver.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
optional<uint64_t> NeoMemoryDiskDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
if(pos % SectorSize != 0)
return nullopt;
if(amount != SectorSize)
return nullopt;
if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) {
// The cache does not have this data, go get it
const uint64_t currentSector = pos / SectorSize;
auto msg = com.waitForMessageSync([&currentSector, &com] {
return com.sendCommand(Command::NeoReadMemory, {
MemoryTypeSD,
uint8_t(currentSector & 0xFF),
uint8_t((currentSector >> 8) & 0xFF),
uint8_t((currentSector >> 16) & 0xFF),
uint8_t((currentSector >> 24) & 0xFF),
uint8_t(SectorSize & 0xFF),
uint8_t((SectorSize >> 8) & 0xFF),
uint8_t((SectorSize >> 16) & 0xFF),
uint8_t((SectorSize >> 24) & 0xFF)
});
}, NeoMemorySDRead, timeout);
if(!msg)
return 0;
const auto sdmsg = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
if(!sdmsg || sdmsg->data.size() != SectorSize) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return nullopt;
}
memcpy(cache.data(), sdmsg->data.data(), SectorSize);
cachedAt = std::chrono::steady_clock::now();
cachePos = pos;
}
memcpy(into, cache.data(), SectorSize);
return SectorSize;
}
optional<uint64_t> NeoMemoryDiskDriver::writeLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, const uint8_t* atomicBuf, const uint8_t* from, uint64_t amount, std::chrono::milliseconds timeout) {
static std::shared_ptr<MessageFilter> NeoMemoryDone = std::make_shared<MessageFilter>(Network::NetID::NeoMemoryWriteDone);
if(pos % SectorSize != 0)
return nullopt;
if(amount != SectorSize)
return nullopt;
// Clear the cache if we're writing to the cached sector
if(pos == cachePos)
cachedAt = std::chrono::time_point<std::chrono::steady_clock>();
// Requesting an atomic operation, but neoMemory does not support it
// Continue on anyway but warn the caller
if(atomicBuf != nullptr)
report(APIEvent::Type::AtomicOperationCompletedNonatomically, NonatomicSeverity);
const uint64_t currentSector = pos / SectorSize;
auto msg = com.waitForMessageSync([&currentSector, &com, from, amount] {
std::vector<uint8_t> command = {
MemoryTypeSD,
uint8_t(currentSector & 0xFF),
uint8_t((currentSector >> 8) & 0xFF),
uint8_t((currentSector >> 16) & 0xFF),
uint8_t((currentSector >> 24) & 0xFF),
uint8_t(SectorSize & 0xFF),
uint8_t((SectorSize >> 8) & 0xFF),
};
command.insert(command.end(), from, from + amount);
return com.sendCommand(Command::NeoWriteMemory, command);
}, NeoMemoryDone, timeout);
if(!msg)
return nullopt;
return SectorSize;
}

View File

@ -0,0 +1,28 @@
#include "icsneo/disk/nulldiskdriver.h"
using namespace icsneo;
using namespace icsneo::Disk;
optional<uint64_t> NullDriver::readLogicalDisk(Communication&, device_eventhandler_t report,
uint64_t, uint8_t*, uint64_t, std::chrono::milliseconds) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return nullopt;
}
optional<uint64_t> NullDriver::readLogicalDiskAligned(Communication&, device_eventhandler_t report,
uint64_t, uint8_t*, uint64_t, std::chrono::milliseconds) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return nullopt;
}
optional<uint64_t> NullDriver::writeLogicalDisk(Communication&, device_eventhandler_t report, ReadDriver&,
uint64_t, const uint8_t*, uint64_t, std::chrono::milliseconds) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return nullopt;
}
optional<uint64_t> NullDriver::writeLogicalDiskAligned(Communication&, device_eventhandler_t report,
uint64_t, const uint8_t*, const uint8_t*, uint64_t, std::chrono::milliseconds) {
report(APIEvent::Type::DiskNotSupported, APIEvent::Severity::Error);
return nullopt;
}

View File

@ -0,0 +1,78 @@
#include "icsneo/disk/plasiondiskreaddriver.h"
#include "icsneo/communication/message/neoreadmemorysdmessage.h"
#include "icsneo/communication/multichannelcommunication.h"
#include <cstring>
using namespace icsneo;
using namespace icsneo::Disk;
optional<uint64_t> PlasionDiskReadDriver::readLogicalDiskAligned(Communication& com, device_eventhandler_t report,
uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout) {
static std::shared_ptr<MessageFilter> NeoMemorySDRead = std::make_shared<MessageFilter>(Network::NetID::NeoMemorySDRead);
if(amount > getBlockSizeBounds().second)
return nullopt;
if(amount % getBlockSizeBounds().first != 0)
return nullopt;
if(pos % getBlockSizeBounds().first != 0)
return nullopt;
if(cachePos != pos || std::chrono::steady_clock::now() > cachedAt + CacheTime) {
uint64_t largeSector = pos / SectorSize;
uint32_t sector = uint32_t(largeSector);
if (largeSector != uint64_t(sector))
return nullopt;
// The cache does not have this data, go get it
std::mutex m;
std::condition_variable cv;
uint32_t copied = 0;
bool error = false;
std::unique_lock<std::mutex> lk(m);
auto cb = com.addMessageCallback(MessageCallback([&](std::shared_ptr<Message> msg) {
std::unique_lock<std::mutex> lk(m);
const auto sdmsg = std::dynamic_pointer_cast<NeoReadMemorySDMessage>(msg);
if(!sdmsg || cache.size() < copied + sdmsg->data.size()) {
error = true;
lk.unlock();
cv.notify_all();
return;
}
// Invalidate the cache here in case we fail half-way through
cachedAt = std::chrono::steady_clock::time_point();
memcpy(cache.data() + copied, sdmsg->data.data(), sdmsg->data.size());
copied += uint32_t(sdmsg->data.size());
if(copied == amount) {
lk.unlock();
cv.notify_all();
}
}, NeoMemorySDRead));
com.rawWrite({
uint8_t(MultiChannelCommunication::CommandType::HostPC_from_SDCC1),
uint8_t(sector & 0xFF),
uint8_t((sector >> 8) & 0xFF),
uint8_t((sector >> 16) & 0xFF),
uint8_t((sector >> 24) & 0xFF),
uint8_t(amount & 0xFF),
uint8_t((amount >> 8) & 0xFF),
});
bool hitTimeout = !cv.wait_for(lk, timeout, [&copied, &error, &amount] { return error || copied == amount; });
com.removeMessageCallback(cb);
if(hitTimeout)
return nullopt;
cachedAt = std::chrono::steady_clock::now();
cachePos = pos;
}
memcpy(into, cache.data(), size_t(amount));
return amount;
}

View File

@ -30,13 +30,13 @@ void printAllDevices() {
if(numDevices == 0) { if(numDevices == 0) {
printf("No devices found! Please scan for new devices.\n"); printf("No devices found! Please scan for new devices.\n");
} }
for(int i = 0; i < numDevices; i++) { for(size_t i = 0; i < numDevices; i++) {
char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = { 0 }; char productDescription[ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION] = { 0 };
size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION; size_t descriptionLength = ICSNEO_DEVICETYPE_LONGEST_DESCRIPTION;
// Updates productDescription and descriptionLength for each device // Updates productDescription and descriptionLength for each device
if(icsneo_describeDevice(devices + i, productDescription, &descriptionLength)) { if(icsneo_describeDevice(devices + i, productDescription, &descriptionLength)) {
printf("[%d] %s\tConnected: ", i + 1, productDescription); printf("[%zd] %s\tConnected: ", i + 1, productDescription);
if(icsneo_isOpen(devices + i)) { if(icsneo_isOpen(devices + i)) {
printf("Yes\t"); printf("Yes\t");
} else printf("No\t"); } else printf("No\t");
@ -52,7 +52,7 @@ void printAllDevices() {
} else printf("Off\n"); } else printf("Off\n");
} else { } else {
printf("Description for device %d not available!\n", i + 1); printf("Description for device %zd not available!\n", i + 1);
} }
} }
} }
@ -66,7 +66,7 @@ size_t scanNewDevices() {
size_t numNewDevices = 99; size_t numNewDevices = 99;
icsneo_findAllDevices(newDevices, &numNewDevices); icsneo_findAllDevices(newDevices, &numNewDevices);
for(int i = 0; i < numNewDevices; ++i) { for(size_t i = 0; i < numNewDevices; ++i) {
devices[numDevices + i] = newDevices[i]; devices[numDevices + i] = newDevices[i];
} }
numDevices += numNewDevices; numDevices += numNewDevices;
@ -112,7 +112,7 @@ void printAPIEvents() {
printf("Event 0x%u: %s\n", events[0].eventNumber, events[0].description); printf("Event 0x%u: %s\n", events[0].eventNumber, events[0].description);
} else { } else {
printf("%d API events found!\n", (int) eventCount); printf("%d API events found!\n", (int) eventCount);
for(int i = 0; i < eventCount; ++i) { for(size_t i = 0; i < eventCount; ++i) {
printf("Event 0x%u: %s\n", events[i].eventNumber, events[i].description); printf("Event 0x%u: %s\n", events[i].eventNumber, events[i].description);
} }
} }
@ -134,7 +134,7 @@ void printDeviceEvents(neodevice_t* device) {
printf("Event 0x%x: %s\n", events[0].eventNumber, events[0].description); printf("Event 0x%x: %s\n", events[0].eventNumber, events[0].description);
} else { } else {
printf("%d device events found!\n", (int) eventCount); printf("%d device events found!\n", (int) eventCount);
for(int i = 0; i < eventCount; ++i) { for(size_t i = 0; i < eventCount; ++i) {
printf("Event 0x%x: %s\n", events[i].eventNumber, events[i].description); printf("Event 0x%x: %s\n", events[i].eventNumber, events[i].description);
} }
} }
@ -196,10 +196,14 @@ const neodevice_t* selectDevice() {
printAllDevices(); printAllDevices();
printf("\n"); printf("\n");
int selectedDeviceNum = 10; size_t selectedDeviceNum = 10;
while(selectedDeviceNum > numDevices) { while(selectedDeviceNum > numDevices) {
char deviceSelection = getCharInput(9, '1', '2', '3', '4', '5', '6', '7', '8', '9'); char deviceSelection = getCharInput(9, '1', '2', '3', '4', '5', '6', '7', '8', '9');
if(deviceSelection < '0') {
printf("Selected device out of range!\n");
continue;
}
selectedDeviceNum = deviceSelection - '0'; selectedDeviceNum = deviceSelection - '0';
if(selectedDeviceNum > numDevices) { if(selectedDeviceNum > numDevices) {
printf("Selected device out of range!\n"); printf("Selected device out of range!\n");
@ -301,7 +305,7 @@ int main() {
// Shifts everything after the removed device 1 index to the left // Shifts everything after the removed device 1 index to the left
bool startResizing = false; bool startResizing = false;
for(int i = 0; i < numDevices; ++i) { for(size_t i = 0; i < numDevices; ++i) {
if(selectedDevice == devices + i) if(selectedDevice == devices + i)
startResizing = true; startResizing = true;
if(startResizing) if(startResizing)
@ -467,11 +471,13 @@ int main() {
// Print out the received messages // Print out the received messages
for(size_t i = 0; i < msgCount; i++) { for(size_t i = 0; i < msgCount; i++) {
neomessage_t* msg = &msgs[i]; const neomessage_t* msg = &msgs[i];
switch(msg->type) { switch(msg->messageType) {
case ICSNEO_NETWORK_TYPE_CAN: // CAN case ICSNEO_MESSAGE_TYPE_FRAME: {
{ const neomessage_frame_t* frame = (neomessage_frame_t*)msg;
neomessage_can_t* canMsg = (neomessage_can_t*) msg; switch(frame->type) {
case ICSNEO_NETWORK_TYPE_CAN: {
neomessage_can_t* canMsg = (neomessage_can_t*)frame;
printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length); printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length);
for(size_t i = 0; i < canMsg->length; i++) { for(size_t i = 0; i < canMsg->length; i++) {
printf("%02x ", canMsg->data[i]); printf("%02x ", canMsg->data[i]);
@ -482,10 +488,18 @@ int main() {
break; break;
} }
default: default:
if(msg->netid != 0) printf("\tMessage on netid %d with length %zu\n", frame->netid, frame->length);
printf("\tMessage on netid %d with length %zu\n", msg->netid, msg->length);
break; break;
} }
break;
}
case ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT: {
const neomessage_can_error_t* cec = (neomessage_can_error_t*)msg;
printf("\tCAN error counts changed, TEC=%d, REC=%d%s", cec->transmitErrorCount, cec->receiveErrorCount,
cec->status.canBusOff ? " (Bus Off)" : "");
break;
}
}
} }
printf("\n"); printf("\n");

View File

@ -182,6 +182,102 @@ std::shared_ptr<icsneo::Device> selectDevice(const std::vector<std::shared_ptr<i
return from.at(selectedDeviceNum - 1); return from.at(selectedDeviceNum - 1);
} }
void printMessage(const std::shared_ptr<icsneo::Message>& message) {
switch(message->type) {
case icsneo::Message::Type::Frame: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
std::cout << "\t\t" << frame->network << ' ';
if(canMessage->isCANFD) {
std::cout << "FD ";
if(!canMessage->baudrateSwitch)
std::cout << "(No BRS) ";
}
// Print the Arbitration ID
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
<< std::setfill('0') << canMessage->arbid;
// Print the DLC
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
// Print the data
for(auto& databyte : canMessage->data)
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n";
break;
}
case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
// Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) {
if(i % 8 == 0)
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
}
std::cout << std::dec << std::endl;
break;
}
case icsneo::Network::Type::ISO9141: {
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
// and that this example loads the device defaults at the very end.
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
std::cout << "\t\t" << isoMessage->network << ' ';
// Print the header bytes
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
// Print the data length
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
// Print the data
for(auto& databyte : isoMessage->data)
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
break;
}
default:
// Ignoring non-network messages
break;
}
break;
} // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << cec->receiveErrorCount
<< " TEC=" << cec->transmitErrorCount << " (" << (cec->busOff ? "" : "Not ") << "Bus Off)" << std::endl;
break;
}
default:
// Ignoring other types of messages
break;
}
}
int main() { int main() {
std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl; std::cout << "Running libicsneo " << icsneo::GetVersion() << std::endl << std::endl;
@ -392,28 +488,8 @@ int main() {
} }
// Print out the received messages // Print out the received messages
for(auto msg : msgs) { for(const auto& msg : msgs)
switch(msg->network.getType()) { printMessage(msg);
case icsneo::Network::Type::CAN:
{
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
std::cout << "\t0x" << std::setfill('0') << std::setw(3) << std::hex << (int) canMsg->arbid << " [" << canMsg->data.size() << "] " << std::dec;
for(auto data : canMsg->data) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int) data << " " << std::dec;
}
std::cout << canMsg->timestamp << std::endl;
break;
}
default:
if(msg->network.getNetID() != icsneo::Network::NetID::Device) {
std::cout << "\tMessage on netid " << msg->network.GetNetIDString(msg->network.getNetID()) << " with length " << msg->data.size() << std::endl;
}
break;
}
}
std::cout << std::endl; std::cout << std::endl;
} }
@ -538,28 +614,8 @@ int main() {
switch(selection) { switch(selection) {
case '1': case '1':
{ {
// Shameless copy-paste from get messages above, demonstrating a callback
int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){ int callbackID = selectedDevice->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> msg){
switch(msg->network.getType()) { printMessage(msg);
case icsneo::Network::Type::CAN:
{
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMsg = std::static_pointer_cast<icsneo::CANMessage>(msg);
std::cout << "\t0x" << std::setfill('0') << std::setw(3) << std::hex << (int) canMsg->arbid << " [" << canMsg->data.size() << "] " << std::dec;
for(auto data : canMsg->data) {
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int) data << " " << std::dec;
}
std::cout << canMsg->timestamp << std::endl;
break;
}
default:
if(msg->network.getNetID() != icsneo::Network::NetID::Device) {
std::cout << "\tMessage on netid " << msg->network.GetNetIDString(msg->network.getNetID()) << " with length " << msg->data.size() << std::endl;
}
break;
}
})); }));
if(callbackID != -1) { if(callbackID != -1) {
@ -636,7 +692,7 @@ int main() {
names.push_back("Ethernet (DoIP) Activation Line"); names.push_back("Ethernet (DoIP) Activation Line");
if(ethAct > 1) { if(ethAct > 1) {
names.back() += ' '; names.back() += ' ';
names.back() += i; names.back() += std::to_string(i);
} }
std::cout << '[' << options.back() << "] " << names.back(); std::cout << '[' << options.back() << "] " << names.back();
const auto val = selectedDevice->getDigitalIO(icsneo::IO::EthernetActivation, i); const auto val = selectedDevice->getDigitalIO(icsneo::IO::EthernetActivation, i);
@ -655,7 +711,7 @@ int main() {
names.push_back("USB Host Power"); names.push_back("USB Host Power");
if(usbHost > 1) { if(usbHost > 1) {
names.back() += ' '; names.back() += ' ';
names.back() += i; names.back() += std::to_string(i);
} }
std::cout << '[' << options.back() << "] " << names.back(); std::cout << '[' << options.back() << "] " << names.back();
const auto val = selectedDevice->getDigitalIO(icsneo::IO::USBHostPower, i); const auto val = selectedDevice->getDigitalIO(icsneo::IO::USBHostPower, i);

View File

@ -126,16 +126,32 @@ int main() {
device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k
// Keep in mind that 20k messages comes quickly at high bus loads! // Keep in mind that 20k messages comes quickly at high bus loads!
// We can transmit messages
std::cout << "\tTransmitting an extended CAN FD frame... ";
auto txMessage5 = std::make_shared<icsneo::CANMessage>();
txMessage5->network = icsneo::Network::NetID::HSCAN;
txMessage5->arbid = 0x1C5001C5;
txMessage5->data.insert(txMessage5->data.end(), {0xaa, 0xbb, 0xcc});
// The DLC will come from the length of the data vector
txMessage5->isExtended = true;
txMessage5->isCANFD = true;
ret = device->transmit(txMessage5); // This will return false if the device does not support CAN FD, or does not have HSCAN
std::cout << (ret ? "OK" : "FAIL") << std::endl;
// We can also register a handler // We can also register a handler
std::cout << "\tStreaming messages in for 3 seconds... " << std::endl; std::cout << "\tStreaming messages in for 3 seconds... " << std::endl;
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation // MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) { auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) {
switch(message->network.getType()) { switch(message->type) {
case icsneo::Message::Type::Frame: {
// A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: { case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely // A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message); auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
std::cout << "\t\tCAN "; std::cout << "\t\t" << frame->network << ' ';
if(canMessage->isCANFD) { if(canMessage->isCANFD) {
std::cout << "FD "; std::cout << "FD ";
if(!canMessage->baudrateSwitch) if(!canMessage->baudrateSwitch)
@ -143,7 +159,8 @@ int main() {
} }
// Print the Arbitration ID // Print the Arbitration ID
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3) << std::setfill('0') << canMessage->arbid; std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
<< std::setfill('0') << canMessage->arbid;
// Print the DLC // Print the DLC
std::cout << std::dec << " [" << canMessage->data.size() << "] "; std::cout << std::dec << " [" << canMessage->data.size() << "] ";
@ -159,7 +176,8 @@ int main() {
case icsneo::Network::Type::Ethernet: { case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message); auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec << ethMessage->data.size() << " bytes on wire\n"; std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n"; std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member // The MACAddress may be printed directly or accessed with the `data` member
@ -204,6 +222,24 @@ int main() {
// Ignoring non-network messages // Ignoring non-network messages
break; break;
} }
break;
} // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
// Print the error counts
std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount)
<< " TEC=" << std::to_string(cec->transmitErrorCount) << " (" << (cec->busOff ? "" : "Not ") << "Bus Off) ";
// Print the timestamp
std::cout << std::dec << '(' << cec->timestamp << " ns since 1/1/2007)\n";
break;
}
default:
// Ignoring other types of messages
break;
}
})); }));
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
device->removeMessageCallback(handler); // Removing the callback means it will not be called anymore device->removeMessageCallback(handler); // Removing the callback means it will not be called anymore

View File

@ -47,6 +47,7 @@ public:
UnsupportedTXNetwork = 0x1011, UnsupportedTXNetwork = 0x1011,
MessageMaxLengthExceeded = 0x1012, MessageMaxLengthExceeded = 0x1012,
ValueNotYetPresent = 0x1013, ValueNotYetPresent = 0x1013,
Timeout = 0x1014,
// Device Events // Device Events
PollingMessageOverflow = 0x2000, PollingMessageOverflow = 0x2000,
@ -79,6 +80,12 @@ public:
NoSerialNumberFW = 0x2027, // A firmware update was already attempted NoSerialNumberFW = 0x2027, // A firmware update was already attempted
NoSerialNumber12V = 0x2028, // The device must be powered with 12V for communication to be established NoSerialNumber12V = 0x2028, // The device must be powered with 12V for communication to be established
NoSerialNumberFW12V = 0x2029, // The device must be powered with 12V for communication to be established, a firmware update was already attempted NoSerialNumberFW12V = 0x2029, // The device must be powered with 12V for communication to be established, a firmware update was already attempted
EthPhyRegisterControlNotAvailable = 0x2030, //The device doesn't support Ethernet PHY MDIO access
DiskNotSupported = 0x2031,
EOFReached = 0x2032,
SettingsDefaultsUsed = 0x2033,
AtomicOperationRetried = 0x2034,
AtomicOperationCompletedNonatomically = 0x2035,
// Transport Events // Transport Events
FailedToRead = 0x3000, FailedToRead = 0x3000,

View File

@ -29,28 +29,10 @@ public:
// If this thread is not in the map, add it to be ignored // If this thread is not in the map, add it to be ignored
// If it is, set it to be ignored // If it is, set it to be ignored
void downgradeErrorsOnCurrentThread() { void downgradeErrorsOnCurrentThread();
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = true;
} else {
downgradedThreads.insert({std::this_thread::get_id(), true});
}
}
// If this thread exists in the map, turn off downgrading // If this thread exists in the map, turn off downgrading
void cancelErrorDowngradingOnCurrentThread() { void cancelErrorDowngradingOnCurrentThread();
if(destructing)
return;
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end()) {
i->second = false;
}
}
bool isDowngradingErrorsOnCurrentThread() const; bool isDowngradingErrorsOnCurrentThread() const;
@ -59,7 +41,7 @@ public:
size_t eventCount(EventFilter filter = EventFilter()) const { size_t eventCount(EventFilter filter = EventFilter()) const {
std::lock_guard<std::mutex> lk(eventsMutex); std::lock_guard<std::mutex> lk(eventsMutex);
return count_internal(filter); return countInternal(filter);
}; };
std::vector<APIEvent> get(EventFilter filter, size_t max = 0) { return get(max, filter); } std::vector<APIEvent> get(EventFilter filter, size_t max = 0) { return get(max, filter); }
@ -73,65 +55,23 @@ public:
APIEvent getLastError(); APIEvent getLastError();
void add(APIEvent event) { void add(APIEvent event);
if(destructing)
return;
if(event.getSeverity() == APIEvent::Severity::Error) {
// if the error was added on a thread that downgrades errors (non-user thread)
std::lock_guard<std::mutex> lk(downgradedThreadsMutex);
auto i = downgradedThreads.find(std::this_thread::get_id());
if(i != downgradedThreads.end() && i->second) {
event.downgradeFromError();
std::unique_lock<std::mutex> eventsLock(eventsMutex);
add_internal_event(event);
// free the lock so that callbacks may modify events
eventsLock.unlock();
runCallbacks(event);
} else {
std::lock_guard<std::mutex> errorsLock(errorsMutex);
add_internal_error(event);
}
} else {
std::unique_lock<std::mutex> eventsLock(eventsMutex);
add_internal_event(event);
// free the lock so that callbacks may modify events
eventsLock.unlock();
runCallbacks(event);
}
}
void add(APIEvent::Type type, APIEvent::Severity severity, const Device* forDevice = nullptr) { void add(APIEvent::Type type, APIEvent::Severity severity, const Device* forDevice = nullptr) {
add(APIEvent(type, severity, forDevice)); add(APIEvent(type, severity, forDevice));
} }
void discard(EventFilter filter = EventFilter()); void discard(EventFilter filter = EventFilter());
void setEventLimit(size_t newLimit) {
std::lock_guard<std::mutex> eventLimitLock(eventLimitMutex);
if(newLimit == eventLimit)
return;
if(newLimit < 10) {
add(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return;
}
eventLimit = newLimit;
std::lock_guard<std::mutex> eventsLock(eventsMutex);
if(enforceLimit())
add_internal_event(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
}
size_t getEventLimit() const { size_t getEventLimit() const {
std::lock_guard<std::mutex> lk(eventLimitMutex); std::lock_guard<std::mutex> lk(eventLimitMutex);
return eventLimit; return eventLimit;
} }
void setEventLimit(size_t newLimit);
private: private:
EventManager() : eventsMutex(), errorsMutex(), downgradedThreadsMutex(), callbacksMutex(), callbackIDMutex(), eventLimitMutex(), downgradedThreads(), callbacks(), events(), lastUserErrors(), eventLimit(10000) {} EventManager() : eventLimit(10000) {}
EventManager(const EventManager &other); EventManager(const EventManager& other); // = delete (not supported everywhere)
EventManager& operator=(const EventManager &other); EventManager& operator=(const EventManager& other); // = delete (not supported everywhere)
// Used by functions for threadsafety // Used by functions for threadsafety
mutable std::mutex eventsMutex; mutable std::mutex eventsMutex;
@ -155,51 +95,15 @@ private:
std::map<std::thread::id, APIEvent> lastUserErrors; std::map<std::thread::id, APIEvent> lastUserErrors;
size_t eventLimit = 10000; size_t eventLimit = 10000;
size_t count_internal(EventFilter filter = EventFilter()) const; size_t countInternal(EventFilter filter = EventFilter()) const;
void runCallbacks(APIEvent event) { void runCallbacks(APIEvent event);
std::lock_guard<std::mutex> lk(callbacksMutex);
for(auto &i : callbacks) {
i.second.callIfMatch(std::make_shared<APIEvent>(event));
}
}
/**
* Places a {id, event} pair into the lastUserErrors
* If the key id already exists in the map, replace the event of that pair with the new one
*/
void add_internal_error(APIEvent event) {
std::thread::id id = std::this_thread::get_id();
auto it = lastUserErrors.find(id);
if(it == lastUserErrors.end())
lastUserErrors.insert({id, event});
else
it->second = event;
}
/** /**
* If events is not full, add the event at the end * If events is not full, add the event at the end
* Otherwise, remove the oldest event, push the event to the back and push a APIEvent::TooManyEvents to the back (in that order) * Otherwise, remove the oldest event, push the event to the back and push a APIEvent::TooManyEvents to the back (in that order)
*/ */
void add_internal_event(APIEvent event) { void addEventInternal(APIEvent event);
// Ensure the event list is at most exactly full (size of eventLimit - 1, leaving room for a potential APIEvent::TooManyEvents)
// Removes any events of type TooManyEvents from the end before checking to avoid duplicates.
enforceLimit();
// We are exactly full, either because the list was truncated or because we were simply full before
if(events.size() == eventLimit - 1) {
// If the event is worth adding
if(event.getType() != APIEvent::Type::TooManyEvents) {
discardOldest(1);
events.push_back(event);
}
events.push_back(APIEvent(APIEvent::Type::TooManyEvents, APIEvent::Severity::EventWarning));
} else {
if (event.getType() != APIEvent::Type::TooManyEvents)
events.push_back(event);
}
}
bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow bool enforceLimit(); // Returns whether the limit enforcement resulted in an overflow

View File

@ -8,6 +8,8 @@ namespace icsneo {
enum class Command : uint8_t { enum class Command : uint8_t {
EnableNetworkCommunication = 0x07, EnableNetworkCommunication = 0x07,
EnableNetworkCommunicationEx = 0x08, EnableNetworkCommunicationEx = 0x08,
NeoReadMemory = 0x40,
NeoWriteMemory = 0x41,
RequestSerialNumber = 0xA1, RequestSerialNumber = 0xA1,
GetMainVersion = 0xA3, // Previously known as RED_CMD_APP_VERSION_REQ GetMainVersion = 0xA3, // Previously known as RED_CMD_APP_VERSION_REQ
SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM SetSettings = 0xA4, // Previously known as RED_CMD_SET_BAUD_REQ, follow up with SaveSettings to write to EEPROM
@ -16,13 +18,27 @@ enum class Command : uint8_t {
UpdateLEDState = 0xA7, UpdateLEDState = 0xA7,
SetDefaultSettings = 0xA8, // Follow up with SaveSettings to write to EEPROM SetDefaultSettings = 0xA8, // Follow up with SaveSettings to write to EEPROM
GetSecondaryVersions = 0xA9, // Previously known as RED_CMD_PERIPHERALS_APP_VERSION_REQ, versions other than the main chip GetSecondaryVersions = 0xA9, // Previously known as RED_CMD_PERIPHERALS_APP_VERSION_REQ, versions other than the main chip
GetLogicalDiskInfo = 0xBB, // Previously known as RED_CMD_GET_SDCARD_INFO
RequestStatusUpdate = 0xBC, RequestStatusUpdate = 0xBC,
ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX
SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR
RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH
GetVBattReq = 0xDF, // Previously known as RED_CMD_VBATT_REQUEST GetVBattReq = 0xDF, // Previously known as RED_CMD_VBATT_REQUEST
MiscControl = 0xE7, MiscControl = 0xE7,
FlexRayControl = 0xF3 Extended = 0xF0,
FlexRayControl = 0xF3,
PHYControlRegisters = 0xEF
};
enum class ExtendedCommand : uint16_t {
GetDiskDetails = 0x0010,
DiskFormatStart = 0x0011,
DiskFormatCancel = 0x0012,
DiskFormatProgress = 0x0013,
DiskFormatUpdate = 0x0014,
Extract = 0x0015,
StartDHCPServer = 0x0016,
StopDHCPServer = 0x0017,
}; };
} }

View File

@ -9,6 +9,7 @@
#include "icsneo/communication/packet.h" #include "icsneo/communication/packet.h"
#include "icsneo/communication/message/callback/messagecallback.h" #include "icsneo/communication/message/callback/messagecallback.h"
#include "icsneo/communication/message/serialnumbermessage.h" #include "icsneo/communication/message/serialnumbermessage.h"
#include "icsneo/communication/message/logicaldiskinfomessage.h"
#include "icsneo/device/deviceversion.h" #include "icsneo/device/deviceversion.h"
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
@ -25,14 +26,14 @@ namespace icsneo {
class Communication { class Communication {
public: public:
// Note that the Packetizer is not created by the constructor,
// and should be done once the Communication module is in place.
Communication( Communication(
device_eventhandler_t report, device_eventhandler_t report,
std::unique_ptr<Driver>&& driver, std::unique_ptr<Driver>&& driver,
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer, std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer,
std::unique_ptr<Encoder>&& e, std::unique_ptr<Encoder>&& e,
std::unique_ptr<Decoder>&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), report(report), driver(std::move(driver)) { std::unique_ptr<Decoder>&& md) : makeConfiguredPacketizer(makeConfiguredPacketizer), encoder(std::move(e)), decoder(std::move(md)), driver(std::move(driver)), report(report) {}
packetizer = makeConfiguredPacketizer();
}
virtual ~Communication(); virtual ~Communication();
bool open(); bool open();
@ -52,14 +53,16 @@ public:
virtual bool sendCommand(Command cmd, bool boolean) { return sendCommand(cmd, std::vector<uint8_t>({ (uint8_t)boolean })); } virtual bool sendCommand(Command cmd, bool boolean) { return sendCommand(cmd, std::vector<uint8_t>({ (uint8_t)boolean })); }
virtual bool sendCommand(Command cmd, std::vector<uint8_t> arguments = {}); virtual bool sendCommand(Command cmd, std::vector<uint8_t> arguments = {});
bool sendCommand(ExtendedCommand cmd, std::vector<uint8_t> arguments = {});
bool getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); bool getSettingsSync(std::vector<uint8_t>& data, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
std::shared_ptr<SerialNumberMessage> getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::shared_ptr<SerialNumberMessage> getSerialNumberSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
optional< std::vector< optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); optional< std::vector< optional<DeviceAppVersion> > > getVersionsSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
std::shared_ptr<LogicalDiskInfoMessage> getLogicalDiskInfoSync(std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
int addMessageCallback(const MessageCallback& cb); int addMessageCallback(const MessageCallback& cb);
bool removeMessageCallback(int id); bool removeMessageCallback(int id);
std::shared_ptr<Message> waitForMessageSync( std::shared_ptr<Message> waitForMessageSync(
MessageFilter f = MessageFilter(), const std::shared_ptr<MessageFilter>& f = {},
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) { std::chrono::milliseconds timeout = std::chrono::milliseconds(50)) {
return waitForMessageSync([](){ return true; }, f, timeout); return waitForMessageSync([](){ return true; }, f, timeout);
} }
@ -67,17 +70,17 @@ public:
// Return false to bail early, in case your initial command failed. // Return false to bail early, in case your initial command failed.
std::shared_ptr<Message> waitForMessageSync( std::shared_ptr<Message> waitForMessageSync(
std::function<bool(void)> onceWaitingDo, std::function<bool(void)> onceWaitingDo,
MessageFilter f = MessageFilter(), const std::shared_ptr<MessageFilter>& f = {},
std::chrono::milliseconds timeout = std::chrono::milliseconds(50)); std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer; std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer;
std::unique_ptr<Packetizer> packetizer; std::unique_ptr<Packetizer> packetizer;
std::unique_ptr<Encoder> encoder; std::unique_ptr<Encoder> encoder;
std::unique_ptr<Decoder> decoder; std::unique_ptr<Decoder> decoder;
std::unique_ptr<Driver> driver;
device_eventhandler_t report; device_eventhandler_t report;
protected: protected:
std::unique_ptr<Driver> driver;
static int messageCallbackIDCounter; static int messageCallbackIDCounter;
std::mutex messageCallbacksLock; std::mutex messageCallbacksLock;
std::map<int, MessageCallback> messageCallbacks; std::map<int, MessageCallback> messageCallbacks;

View File

@ -24,9 +24,10 @@ public:
virtual void awaitModeChangeComplete() {} virtual void awaitModeChangeComplete() {}
virtual bool isDisconnected() { return disconnected; }; virtual bool isDisconnected() { return disconnected; };
virtual bool close() = 0; virtual bool close() = 0;
virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0); bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
virtual bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0); bool readWait(std::vector<uint8_t>& bytes, std::chrono::milliseconds timeout = std::chrono::milliseconds(100), size_t limit = 0);
virtual bool write(const std::vector<uint8_t>& bytes); bool write(const std::vector<uint8_t>& bytes);
virtual bool isEthernet() const { return false; }
device_eventhandler_t report; device_eventhandler_t report;
@ -44,8 +45,15 @@ protected:
LAUNCH, LAUNCH,
WAIT WAIT
}; };
virtual void readTask() = 0; virtual void readTask() = 0;
virtual void writeTask() = 0; virtual void writeTask() = 0;
// Overridable in case the driver doesn't want to use writeTask and writeQueue
virtual bool writeQueueFull() { return writeQueue.size_approx() > writeQueueSize; }
virtual bool writeQueueAlmostFull() { return writeQueue.size_approx() > (writeQueueSize * 3 / 4); }
virtual bool writeInternal(const std::vector<uint8_t>& b) { return writeQueue.enqueue(WriteOperation(b)); }
moodycamel::BlockingConcurrentQueue<uint8_t> readQueue; moodycamel::BlockingConcurrentQueue<uint8_t> readQueue;
moodycamel::BlockingConcurrentQueue<WriteOperation> writeQueue; moodycamel::BlockingConcurrentQueue<WriteOperation> writeQueue;
std::thread readThread, writeThread; std::thread readThread, writeThread;

View File

@ -19,12 +19,11 @@ class Encoder {
public: public:
Encoder(device_eventhandler_t report) : report(report) {} Encoder(device_eventhandler_t report) : report(report) {}
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message); bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, const std::shared_ptr<Message>& message);
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, bool boolean) {
return encode(packetizer, result, cmd, std::vector<uint8_t>({ (uint8_t)boolean }));
}
bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments = {}); bool encode(const Packetizer& packetizer, std::vector<uint8_t>& result, Command cmd, std::vector<uint8_t> arguments = {});
bool supportCANFD = false; bool supportCANFD = false;
bool supportEthPhy = false;
private: private:
device_eventhandler_t report; device_eventhandler_t report;
}; };

View File

@ -18,6 +18,8 @@ namespace icsneo {
*/ */
class EthernetPacketizer { class EthernetPacketizer {
public: public:
static const size_t MaxPacketLength;
EthernetPacketizer(device_eventhandler_t report) : report(report) {} EthernetPacketizer(device_eventhandler_t report) : report(report) {}
/** /**
@ -25,7 +27,7 @@ public:
* outputDown to get the results. Passing in multiple * outputDown to get the results. Passing in multiple
* packets may result in better packing. * packets may result in better packing.
*/ */
void inputDown(std::vector<uint8_t> bytes); void inputDown(std::vector<uint8_t> bytes, bool first = true);
std::vector< std::vector<uint8_t> > outputDown(); std::vector< std::vector<uint8_t> > outputDown();
/** /**
@ -47,6 +49,7 @@ public:
uint8_t srcMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF }; uint8_t srcMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF };
uint16_t etherType = 0xCAB1; // Big endian, Should be 0xCAB1 or 0xCAB2 uint16_t etherType = 0xCAB1; // Big endian, Should be 0xCAB1 or 0xCAB2
uint32_t icsEthernetHeader = 0xAAAA5555; // Big endian, Should be 0xAAAA5555 uint32_t icsEthernetHeader = 0xAAAA5555; // Big endian, Should be 0xAAAA5555
uint16_t payloadSize = 0; // If this is a multi-piece message, this is the size of the expected reassembly
// At this point in the packet, there is a 16-bit payload size, little endian // At this point in the packet, there is a 16-bit payload size, little endian
// This is calculated from payload size in getBytestream // This is calculated from payload size in getBytestream
uint16_t packetNumber = 0; uint16_t packetNumber = 0;
@ -58,6 +61,7 @@ public:
uint8_t hostMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF }; uint8_t hostMAC[6] = { 0x00, 0xFC, 0x70, 0xFF, 0xFF, 0xFF };
uint8_t deviceMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint8_t deviceMAC[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
bool allowInPacketsFromAnyMAC = false; // Used when discovering devices
private: private:
bool reassembling = false; bool reassembling = false;
@ -66,9 +70,11 @@ private:
uint16_t sequenceDown = 0; uint16_t sequenceDown = 0;
std::vector<uint8_t> processedUpBytes; std::vector<uint8_t> processedUpBytes;
std::vector< std::vector<uint8_t> > processedDownPackets; std::vector<EthernetPacket> processedDownPackets;
device_eventhandler_t report; device_eventhandler_t report;
EthernetPacket& newSendPacket(bool first);
}; };
} }

View File

@ -14,12 +14,20 @@ class MessageCallback {
public: public:
typedef std::function< void( std::shared_ptr<Message> ) > fn_messageCallback; typedef std::function< void( std::shared_ptr<Message> ) > fn_messageCallback;
MessageCallback(fn_messageCallback cb, std::shared_ptr<MessageFilter> f) : callback(cb), filter(f) {} MessageCallback(fn_messageCallback cb, std::shared_ptr<MessageFilter> f)
MessageCallback(fn_messageCallback cb, MessageFilter f = MessageFilter()) : callback(cb), filter(std::make_shared<MessageFilter>(f)) {} : callback(cb), filter(f ? f : std::make_shared<MessageFilter>()) {
if(!cb)
throw std::bad_function_call();
}
MessageCallback(fn_messageCallback cb, MessageFilter f = MessageFilter())
: MessageCallback(cb, std::make_shared<MessageFilter>(f)) {}
// Allow the filter to be placed first if the user wants (maybe in the case of a lambda) // Allow the filter to be placed first if the user wants (maybe in the case of a lambda)
MessageCallback(std::shared_ptr<MessageFilter> f, fn_messageCallback cb) : callback(cb), filter(f) {} MessageCallback(std::shared_ptr<MessageFilter> f, fn_messageCallback cb)
MessageCallback(MessageFilter f, fn_messageCallback cb) : callback(cb), filter(std::make_shared<MessageFilter>(f)) {} : MessageCallback(cb, f) {}
MessageCallback(MessageFilter f, fn_messageCallback cb)
: MessageCallback(cb, std::make_shared<MessageFilter>(f)) {}
virtual bool callIfMatch(const std::shared_ptr<Message>& message) const { virtual bool callIfMatch(const std::shared_ptr<Message>& message) const {
bool ret = filter->match(message); bool ret = filter->match(message);
@ -31,8 +39,8 @@ public:
const fn_messageCallback& getCallback() const { return callback; } const fn_messageCallback& getCallback() const { return callback; }
protected: protected:
fn_messageCallback callback; const fn_messageCallback callback;
std::shared_ptr<MessageFilter> filter; const std::shared_ptr<MessageFilter> filter;
}; };
} }

View File

@ -0,0 +1,25 @@
#ifndef __CANERRORCOUNTMESSAGE_H_
#define __CANERRORCOUNTMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
namespace icsneo {
class CANErrorCountMessage : public Message {
public:
CANErrorCountMessage(uint8_t tec, uint8_t rec, bool busOffFlag)
: Message(Message::Type::CANErrorCount), transmitErrorCount(tec), receiveErrorCount(rec), busOff(busOffFlag){}
Network network;
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
bool busOff;
};
}
#endif // __cplusplus
#endif

View File

@ -7,7 +7,7 @@
namespace icsneo { namespace icsneo {
class CANMessage : public Message { class CANMessage : public Frame {
public: public:
uint32_t arbid; uint32_t arbid;
uint8_t dlcOnWire; uint8_t dlcOnWire;

View File

@ -31,7 +31,7 @@ struct MACAddress {
} }
}; };
class EthernetMessage : public Message { class EthernetMessage : public Frame {
public: public:
bool preemptionEnabled = false; bool preemptionEnabled = false;
uint8_t preemptionFlags = 0; uint8_t preemptionFlags = 0;

View File

@ -0,0 +1,51 @@
#ifndef __ETHPHYMESSAGE_H__
#define __ETHPHYMESSAGE_H__
#ifdef __cplusplus
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/packet.h"
#include "icsneo/api/eventmanager.h"
#include <vector>
#include <memory>
namespace icsneo {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#endif
struct PhyMessage {
bool Enabled;
bool WriteEnable;
bool Clause45Enable;
uint8_t version;
union {
Clause22Message clause22;
Clause45Message clause45;
};
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
//Internal message which provides an interface with device ethernet PHY registers,
//with Clause22 and Clause45 message support
class EthPhyMessage : public Message {
public:
EthPhyMessage() : Message(Message::Type::EthernetPhyRegister) {}
bool appendPhyMessage(bool writeEnable, bool clause45, uint8_t phyAddrOrPort, uint8_t pageOrDevice, uint16_t regAddr, uint16_t regVal = 0x0000u, bool enabled = true);
bool appendPhyMessage(std::shared_ptr<PhyMessage> message);
size_t getMessageCount() const;
std::vector<std::shared_ptr<PhyMessage>> messages;
};
}
#endif // __cplusplus
#endif

View File

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

View File

@ -14,10 +14,12 @@ namespace icsneo {
class Main51MessageFilter : public MessageFilter { class Main51MessageFilter : public MessageFilter {
public: public:
Main51MessageFilter() : MessageFilter(Network::NetID::Main51), command(INVALID_COMMAND) {} Main51MessageFilter() : MessageFilter(Message::Type::Main51), command(INVALID_COMMAND) {}
Main51MessageFilter(Command command) : MessageFilter(Network::NetID::Main51), command(command) {} // Don't filter on Type::Main51 for Command as some Commands have their own type
// We still guarantee it's a Main51Message if it matches because of the dynamic_pointer_cast below
Main51MessageFilter(Command command) : command(command) { includeInternalInAny = true; }
bool match(const std::shared_ptr<Message>& message) const { bool match(const std::shared_ptr<Message>& message) const override {
if(!MessageFilter::match(message)) { if(!MessageFilter::match(message)) {
//std::cout << "message filter did not match base for " << message->network << std::endl; //std::cout << "message filter did not match base for " << message->network << std::endl;
return false; return false;

View File

@ -12,26 +12,45 @@ namespace icsneo {
class MessageFilter { class MessageFilter {
public: public:
MessageFilter() {} MessageFilter() {}
MessageFilter(Network::Type type) : type(type) {} MessageFilter(Message::Type type) : includeInternalInAny(neomessagetype_t(type) & 0x8000), messageType(type) {}
MessageFilter(Network::NetID netid) : type(Network::GetTypeOfNetID(netid)), netid(netid) {} MessageFilter(Network::NetID netid) : MessageFilter(Network::GetTypeOfNetID(netid), netid) {}
virtual ~MessageFilter() {} MessageFilter(Network::Type type, Network::NetID net = Network::NetID::Any) : networkType(type), netid(net) {
// If a Network::Type::Internal is used, we want to also get internal Message::Types
// The NetID we want may be in there
includeInternalInAny = (networkType == Network::Type::Internal);
}
virtual ~MessageFilter() = default;
// When getting "all" types of messages, include the ones marked as "internal only" // When getting "all" types of messages, include the ones marked as "internal only"
bool includeInternalInAny = false; bool includeInternalInAny = false;
virtual bool match(const std::shared_ptr<Message>& message) const { virtual bool match(const std::shared_ptr<Message>& message) const {
if(!matchType(message->network.getType())) if(!matchMessageType(message->type))
return false; return false;
if(!matchNetID(message->network.getNetID()))
if(message->type == Message::Type::Frame || message->type == Message::Type::Main51 ||
message->type == Message::Type::RawMessage || message->type == Message::Type::ReadSettings) {
RawMessage& frame = *static_cast<RawMessage*>(message.get());
if(!matchNetworkType(frame.network.getType()))
return false; return false;
if(!matchNetID(frame.network.getNetID()))
return false;
}
return true; return true;
} }
private: protected:
Network::Type type = Network::Type::Any; Message::Type messageType = Message::Type::Invalid; // Used here for "any"
bool matchType(Network::Type mtype) const { bool matchMessageType(Message::Type mtype) const {
if(type == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny)) if(messageType == Message::Type::Invalid && ((neomessagetype_t(mtype) & 0x8000) == 0 || includeInternalInAny))
return true; return true;
return type == mtype; return messageType == mtype;
}
Network::Type networkType = Network::Type::Any;
bool matchNetworkType(Network::Type mtype) const {
if(networkType == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny))
return true;
return networkType == mtype;
} }
Network::NetID netid = Network::NetID::Any; Network::NetID netid = Network::NetID::Any;

View File

@ -23,7 +23,7 @@ public:
uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize); uint8_t controller, uint16_t bufferId, const std::vector<uint8_t>& data, uint16_t desiredSize);
FlexRayControlMessage(const Packet& packet); FlexRayControlMessage(const Packet& packet);
virtual ~FlexRayControlMessage() = default;
bool decoded = false; bool decoded = false;
uint8_t controller = 0xff; // Controller index, either 0 or 1 uint8_t controller = 0xff; // Controller index, either 0 or 1
FlexRay::Opcode opcode = FlexRay::Opcode::Unknown; FlexRay::Opcode opcode = FlexRay::Opcode::Unknown;

View File

@ -10,7 +10,7 @@
namespace icsneo { namespace icsneo {
class FlexRayMessage : public Message { class FlexRayMessage : public Frame {
public: public:
uint16_t slotid = 0; uint16_t slotid = 0;
double tsslen = 0; double tsslen = 0;

View File

@ -8,7 +8,7 @@
namespace icsneo { namespace icsneo {
class ISO9141Message : public Message { class ISO9141Message : public Frame {
public: public:
std::array<uint8_t, 3> header; std::array<uint8_t, 3> header;
bool isInit = false; bool isInit = false;

View File

@ -0,0 +1,29 @@
#ifndef __LOGICALDISKINFOMESSAGE_H_
#define __LOGICALDISKINFOMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include <cstdint>
namespace icsneo {
class LogicalDiskInfoMessage : public Message {
public:
LogicalDiskInfoMessage(bool isConnected, uint32_t numSectors, uint32_t numHidden, uint32_t sectorSize) :
Message(Message::Type::LogicalDiskInfo), connected(isConnected), sectors(numSectors),
hiddenSectors(numHidden), bytesPerSector(sectorSize) {}
const bool connected;
const uint32_t sectors;
const uint32_t hiddenSectors;
const uint32_t bytesPerSector;
uint64_t getReportedSize() const { return uint64_t(sectors) * bytesPerSector; }
};
}
#endif // __cplusplus
#endif

View File

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

View File

@ -1,6 +1,9 @@
#ifndef __MESSAGE_H_ #ifndef __MESSAGE_H_
#define __MESSAGE_H_ #define __MESSAGE_H_
#include <stdint.h>
typedef uint16_t neomessagetype_t;
#ifdef __cplusplus #ifdef __cplusplus
#include "icsneo/communication/network.h" #include "icsneo/communication/network.h"
@ -10,10 +13,44 @@ namespace icsneo {
class Message { class Message {
public: public:
enum class Type : neomessagetype_t {
Frame = 0,
CANErrorCount = 0x100,
// Past 0x8000 are all for internal use only
Invalid = 0x8000,
RawMessage = 0x8001,
ReadSettings = 0x8002,
ResetStatus = 0x8003,
DeviceVersion = 0x8004,
Main51 = 0x8005,
FlexRayControl = 0x8006,
EthernetPhyRegister = 0x8007,
LogicalDiskInfo = 0x8008,
};
Message(Type t) : type(t) {}
virtual ~Message() = default; virtual ~Message() = default;
const Type type;
uint64_t timestamp = 0;
};
class RawMessage : public Message {
public:
RawMessage(Message::Type type = Message::Type::RawMessage) : Message(type) {}
RawMessage(Message::Type type, Network net) : Message(type), network(net) {}
RawMessage(Network net) : Message(Message::Type::RawMessage), network(net) {}
RawMessage(Network net, std::vector<uint8_t> d) : Message(Message::Type::RawMessage), network(net), data(d) {}
Network network; Network network;
std::vector<uint8_t> data; std::vector<uint8_t> data;
uint64_t timestamp = 0; };
class Frame : public RawMessage {
public:
Frame() : RawMessage(Message::Type::Frame) {}
uint16_t description = 0; uint16_t description = 0;
bool transmitted = false; bool transmitted = false;
bool error = false; bool error = false;
@ -23,4 +60,18 @@ public:
#endif // __cplusplus #endif // __cplusplus
#ifdef __ICSNEOC_H_
#define ICSNEO_MESSAGE_TYPE_FRAME (0x0)
#define ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT (0x100)
#define ICSNEO_MESSAGE_TYPE_INVALID (0x8000)
#define ICSNEO_MESSAGE_TYPE_RAW_MESSAGE (0x8001)
#define ICSNEO_MESSAGE_TYPE_READ_SETTINGS (0x8002)
#define ICSNEO_MESSAGE_TYPE_RESET_STATUS (0x8003)
#define ICSNEO_MESSAGE_TYPE_DEVICE_VERSION (0x8004)
#define ICSNEO_MESSAGE_TYPE_MAIN51 (0x8005)
#define ICSNEO_MESSAGE_TYPE_FLEXRAY_CONTROL (0x8006)
#endif // __ICSNEOC_H_
#endif #endif

View File

@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "icsneo/communication/network.h" #include "icsneo/communication/network.h"
#include "icsneo/communication/message/message.h"
#pragma pack(push, 1) #pragma pack(push, 1)
@ -18,12 +19,12 @@ typedef union {
uint32_t extendedFrame : 1; uint32_t extendedFrame : 1;
uint32_t remoteFrame : 1; uint32_t remoteFrame : 1;
uint32_t crcError : 1; uint32_t crcError : 1;
uint32_t canErrorPassive : 1; uint32_t canErrorPassive : 1; // Occupies the same space as headerCRCError
uint32_t incompleteFrame : 1; uint32_t incompleteFrame : 1;
uint32_t lostArbitration : 1; uint32_t lostArbitration : 1;
uint32_t undefinedError : 1; uint32_t undefinedError : 1;
uint32_t canBusOff : 1; uint32_t canBusOff : 1;
uint32_t canErrorWarning : 1; uint32_t canBusRecovered : 1;
uint32_t canBusShortedPlus : 1; uint32_t canBusShortedPlus : 1;
uint32_t canBusShortedGround : 1; uint32_t canBusShortedGround : 1;
uint32_t checksumError : 1; uint32_t checksumError : 1;
@ -101,24 +102,34 @@ typedef union {
#endif #endif
typedef struct { typedef struct {
neomessage_statusbitfield_t status; uint8_t _reserved1[16];
uint64_t timestamp; uint64_t timestamp;
uint64_t timestampReserved; uint64_t _reservedTimestamp;
const uint8_t* data; uint8_t _reserved2[sizeof(size_t) * 2 + 7 + sizeof(neonetid_t) + sizeof(neonettype_t)];
size_t length; neomessagetype_t messageType;
uint8_t header[4]; uint8_t _reserved3[12];
neonetid_t netid;
neonettype_t type;
uint8_t reserved0;
uint16_t description;
uint8_t reserved1[14];
} neomessage_t; // 72 bytes total } neomessage_t; // 72 bytes total
// Any time you add another neomessage_*_t type, make sure to add it to the static_asserts below! // Any time you add another neomessage_*_t type, make sure to add it to the static_asserts below!
typedef struct { typedef struct {
neomessage_statusbitfield_t status; neomessage_statusbitfield_t status;
uint64_t timestamp; uint64_t timestamp;
uint64_t timestampReserved; uint64_t _reservedTimestamp;
const uint8_t* data;
size_t length;
uint8_t header[4];
neonetid_t netid;
neonettype_t type;
uint8_t _reserved0;
uint16_t description;
neomessagetype_t messageType;
uint8_t _reserved1[12];
} neomessage_frame_t;
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t _reservedTimestamp;
const uint8_t* data; const uint8_t* data;
size_t length; size_t length;
uint32_t arbid; uint32_t arbid;
@ -126,22 +137,38 @@ typedef struct {
neonettype_t type; neonettype_t type;
uint8_t dlcOnWire; uint8_t dlcOnWire;
uint16_t description; uint16_t description;
uint8_t reserved[14]; neomessagetype_t messageType;
uint8_t _reserved1[12];
} neomessage_can_t; } neomessage_can_t;
typedef struct { typedef struct {
neomessage_statusbitfield_t status; neomessage_statusbitfield_t status;
uint64_t timestamp; uint64_t timestamp;
uint64_t timestampReserved; uint64_t _reservedTimestamp;
size_t _reserved2[2];
uint8_t transmitErrorCount;
uint8_t receiveErrorCount;
uint8_t _reserved3[5];
neonetid_t netid;
neonettype_t type;
neomessagetype_t messageType;
uint8_t _reserved4[12];
} neomessage_can_error_t;
typedef struct {
neomessage_statusbitfield_t status;
uint64_t timestamp;
uint64_t _reservedTimestamp;
const uint8_t* data; const uint8_t* data;
size_t length; size_t length;
uint8_t preemptionFlags; uint8_t preemptionFlags;
uint8_t reservedHeader[3]; uint8_t _reservedHeader[3];
neonetid_t netid; neonetid_t netid;
neonettype_t type; neonettype_t type;
uint8_t reserved0; uint8_t _reserved0;
uint16_t description; uint16_t description;
uint8_t reserved1[14]; neomessagetype_t messageType;
uint8_t _reserved1[12];
} neomessage_eth_t; } neomessage_eth_t;
#pragma pack(pop) #pragma pack(pop)
@ -151,7 +178,9 @@ typedef struct {
#include <memory> #include <memory>
static_assert(sizeof(neomessage_t) == (56 + sizeof(void*) + sizeof(size_t)), "neomessage_t size is incorrect! Changing size will break compatibility with existing C API programs."); static_assert(sizeof(neomessage_t) == (56 + sizeof(void*) + sizeof(size_t)), "neomessage_t size is incorrect! Changing size will break compatibility with existing C API programs.");
static_assert(sizeof(neomessage_frame_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Base frame is not)");
static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN is not)"); static_assert(sizeof(neomessage_can_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN is not)");
static_assert(sizeof(neomessage_can_error_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (CAN error is not)");
static_assert(sizeof(neomessage_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)"); static_assert(sizeof(neomessage_eth_t) == sizeof(neomessage_t), "All types of neomessage_t must be the same size! (Ethernet is not)");
namespace icsneo { namespace icsneo {

View File

@ -0,0 +1,20 @@
#ifndef __READMEMORYMESSAGE_H_
#define __READMEMORYMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
namespace icsneo {
class NeoReadMemorySDMessage : public RawMessage {
public:
NeoReadMemorySDMessage() : RawMessage(Message::Type::RawMessage, Network::NetID::NeoMemorySDRead) {}
uint32_t startAddress = 0;
};
}
#endif // __cplusplus
#endif

View File

@ -8,9 +8,9 @@
namespace icsneo { namespace icsneo {
class ReadSettingsMessage : public Message { class ReadSettingsMessage : public RawMessage {
public: public:
virtual ~ReadSettingsMessage() = default; ReadSettingsMessage() : RawMessage(Message::Type::ReadSettings, Network::NetID::ReadSettings) {}
enum class Response : uint8_t { enum class Response : uint8_t {
OK = 0, OK = 0,
@ -19,7 +19,8 @@ public:
InvalidSubversion = 3, InvalidSubversion = 3,
NotEnoughMemory = 4, NotEnoughMemory = 4,
APIFailure = 5, APIFailure = 5,
APIUnsupported = 6 APIUnsupported = 6,
OKDefaultsUsed = 7, // Got the settings okay, but the defaults were used (after firmware upgrade or a checksum error)
}; };
Response response; Response response;

View File

@ -5,14 +5,15 @@
#include "icsneo/communication/message/main51message.h" #include "icsneo/communication/message/main51message.h"
#include "icsneo/communication/command.h" #include "icsneo/communication/command.h"
#include "icsneo/platform/optional.h"
#include <string> #include <string>
namespace icsneo { namespace icsneo {
class ResetStatusMessage : public Message { class ResetStatusMessage : public Message {
public: public:
ResetStatusMessage() : Message() {} ResetStatusMessage() : Message(Message::Type::ResetStatus) {}
virtual ~ResetStatusMessage() = default;
uint16_t mainLoopTime; uint16_t mainLoopTime;
uint16_t maxMainLoopTime; uint16_t maxMainLoopTime;
bool justReset; bool justReset;
@ -28,8 +29,8 @@ public:
bool cmTooBig; bool cmTooBig;
bool hidUsbState; bool hidUsbState;
bool fpgaUsbState; bool fpgaUsbState;
uint16_t busVoltage; icsneo::optional<uint16_t> busVoltage;
uint16_t deviceTemperature; icsneo::optional<uint16_t> deviceTemperature;
}; };
} }

View File

@ -11,13 +11,18 @@ namespace icsneo {
class VersionMessage : public Message { class VersionMessage : public Message {
public: public:
VersionMessage(bool main) : MainChip(main) { network = Network::NetID::Main51; } enum Chip : uint8_t {
MainChip,
SecondaryChips
};
// If true, the included version is for the main chip VersionMessage(Chip chip) : Message(Message::Type::DeviceVersion), ForChip(chip) {}
const bool MainChip;
// nullopt here indicates invalid // nullopt here indicates invalid
std::vector< optional<DeviceAppVersion> > Versions; std::vector< optional<DeviceAppVersion> > Versions;
// What chips the versions are for
const Chip ForChip;
}; };
} }

View File

@ -24,10 +24,6 @@ public:
void joinThreads() override; void joinThreads() override;
bool sendPacket(std::vector<uint8_t>& bytes) override; bool sendPacket(std::vector<uint8_t>& bytes) override;
protected:
bool preprocessPacket(std::deque<uint8_t>& usbReadFifo);
private:
enum class CommandType : uint8_t { enum class CommandType : uint8_t {
PlasmaReadRequest = 0x10, // Status read request to HSC PlasmaReadRequest = 0x10, // Status read request to HSC
PlasmaStatusResponse = 0x11, // Status response by HSC PlasmaStatusResponse = 0x11, // Status response by HSC
@ -49,6 +45,10 @@ private:
Microblaze_to_HostPC = 0x81 // Microblaze processor data to host PC Microblaze_to_HostPC = 0x81 // Microblaze processor data to host PC
}; };
protected:
bool preprocessPacket(std::deque<uint8_t>& usbReadFifo);
private:
static bool CommandTypeIsValid(CommandType cmd) { static bool CommandTypeIsValid(CommandType cmd) {
switch(cmd) { switch(cmd) {
case CommandType::PlasmaReadRequest: case CommandType::PlasmaReadRequest:
@ -77,8 +77,10 @@ private:
static bool CommandTypeHasAddress(CommandType cmd) { static bool CommandTypeHasAddress(CommandType cmd) {
// Check CommandTypeIsValid before this, you will get false on an invalid command // Check CommandTypeIsValid before this, you will get false on an invalid command
switch(cmd) { switch(cmd) {
case CommandType::SDCC1_to_HostPC: case CommandType::HostPC_to_SDCC1:
case CommandType::SDCC2_to_HostPC: case CommandType::HostPC_from_SDCC1:
case CommandType::HostPC_to_SDCC2:
case CommandType::HostPC_from_SDCC2:
return true; return true;
default: default:
return false; return false;

View File

@ -41,9 +41,9 @@ public:
RED_EXT_MEMORYREAD = 20, RED_EXT_MEMORYREAD = 20,
RED_INT_MEMORYREAD = 21, RED_INT_MEMORYREAD = 21,
RED_DFLASH_READ = 22, RED_DFLASH_READ = 22,
RED_SDCARD_READ = 23, NeoMemorySDRead = 23, // Response from NeoMemory (MemoryTypeSD)
CAN_ERRBITS = 24, CAN_ERRBITS = 24,
RED_DFLASH_WRITE_DONE = 25, NeoMemoryWriteDone = 25,
RED_WAVE_CAN1_LOGICAL = 26, RED_WAVE_CAN1_LOGICAL = 26,
RED_WAVE_CAN2_LOGICAL = 27, RED_WAVE_CAN2_LOGICAL = 27,
RED_WAVE_LIN1_LOGICAL = 28, RED_WAVE_LIN1_LOGICAL = 28,
@ -117,6 +117,8 @@ public:
HSCAN7 = 97, HSCAN7 = 97,
LIN6 = 98, LIN6 = 98,
LSFTCAN2 = 99, LSFTCAN2 = 99,
LogicalDiskInfo = 187,
EthPHYControl = 239,
FlexRayControl = 243, FlexRayControl = 243,
HW_COM_Latency_Test = 512, HW_COM_Latency_Test = 512,
DeviceStatus = 513, DeviceStatus = 513,
@ -270,6 +272,10 @@ public:
case NetID::FlexRayControl: case NetID::FlexRayControl:
case NetID::Main51: case NetID::Main51:
case NetID::ReadSettings: case NetID::ReadSettings:
case NetID::LogicalDiskInfo:
case NetID::EthPHYControl:
case NetID::NeoMemorySDRead:
case NetID::NeoMemoryWriteDone:
return Type::Internal; return Type::Internal;
case NetID::Invalid: case NetID::Invalid:
case NetID::Any: case NetID::Any:
@ -358,12 +364,12 @@ public:
return "RED_INT_MEMORYREAD"; return "RED_INT_MEMORYREAD";
case NetID::RED_DFLASH_READ: case NetID::RED_DFLASH_READ:
return "RED_DFLASH_READ"; return "RED_DFLASH_READ";
case NetID::RED_SDCARD_READ: case NetID::NeoMemorySDRead:
return "RED_SDCARD_READ"; return "NeoMemorySDRead";
case NetID::CAN_ERRBITS: case NetID::CAN_ERRBITS:
return "CAN_ERRBITS"; return "CAN_ERRBITS";
case NetID::RED_DFLASH_WRITE_DONE: case NetID::NeoMemoryWriteDone:
return "RED_DFLASH_WRITE_DONE"; return "NeoMemoryWriteDone";
case NetID::RED_WAVE_CAN1_LOGICAL: case NetID::RED_WAVE_CAN1_LOGICAL:
return "RED_WAVE_CAN1_LOGICAL"; return "RED_WAVE_CAN1_LOGICAL";
case NetID::RED_WAVE_CAN2_LOGICAL: case NetID::RED_WAVE_CAN2_LOGICAL:
@ -504,6 +510,10 @@ public:
return "LIN 6"; return "LIN 6";
case NetID::LSFTCAN2: case NetID::LSFTCAN2:
return "LSFTCAN 2"; return "LSFTCAN 2";
case NetID::LogicalDiskInfo:
return "Logical Disk Information";
case NetID::EthPHYControl:
return "Ethernet PHY Register Control";
case NetID::FlexRayControl: case NetID::FlexRayControl:
return "FlexRay Control"; return "FlexRay Control";
case NetID::HW_COM_Latency_Test: case NetID::HW_COM_Latency_Test:
@ -826,9 +836,9 @@ private:
#define ICSNEO_NETID_RED_EXT_MEMORYREAD 20 #define ICSNEO_NETID_RED_EXT_MEMORYREAD 20
#define ICSNEO_NETID_RED_INT_MEMORYREAD 21 #define ICSNEO_NETID_RED_INT_MEMORYREAD 21
#define ICSNEO_NETID_RED_DFLASH_READ 22 #define ICSNEO_NETID_RED_DFLASH_READ 22
#define ICSNEO_NETID_RED_SDCARD_READ 23 #define ICSNEO_NETID_NEOMEMORY_SD_READ 23
#define ICSNEO_NETID_CAN_ERRBITS 24 #define ICSNEO_NETID_CAN_ERRBITS 24
#define ICSNEO_NETID_RED_DFLASH_WRITE_DONE 25 #define ICSNEO_NETID_NEOMEMORY_WRITE_DONE 25
#define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL 26 #define ICSNEO_NETID_RED_WAVE_CAN1_LOGICAL 26
#define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL 27 #define ICSNEO_NETID_RED_WAVE_CAN2_LOGICAL 27
#define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL 28 #define ICSNEO_NETID_RED_WAVE_LIN1_LOGICAL 28
@ -902,6 +912,8 @@ private:
#define ICSNEO_NETID_HSCAN7 97 #define ICSNEO_NETID_HSCAN7 97
#define ICSNEO_NETID_LIN6 98 #define ICSNEO_NETID_LIN6 98
#define ICSNEO_NETID_LSFTCAN2 99 #define ICSNEO_NETID_LSFTCAN2 99
#define ICSNEO_NETID_LOGICAL_DISK_INFO 187
#define ICSNEO_NETID_ETH_PHY_CONTROL 239
#define ICSNEO_NETID_FLEXRAY_CONTROL 243 #define ICSNEO_NETID_FLEXRAY_CONTROL 243
#define ICSNEO_NETID_HW_COM_LATENCY_TEST 512 #define ICSNEO_NETID_HW_COM_LATENCY_TEST 512
#define ICSNEO_NETID_DEVICE_STATUS 513 #define ICSNEO_NETID_DEVICE_STATUS 513

View File

@ -13,7 +13,7 @@ namespace icsneo {
typedef uint16_t icscm_bitfield; typedef uint16_t icscm_bitfield;
struct HardwareCANPacket { struct HardwareCANPacket {
static std::shared_ptr<CANMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream); static std::shared_ptr<Message> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report); static bool EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
struct { struct {

View File

@ -0,0 +1,81 @@
#ifndef __ETHPHYREGPACKET_H__
#define __ETHPHYREGPACKET_H__
#ifdef __cplusplus
#include "icsneo/api/eventmanager.h"
#include <cstdint>
#include <memory>
namespace icsneo
{
class Packetizer;
class EthPhyMessage;
#pragma pack(push, 1)
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#endif
struct PhyRegisterHeader_t {
uint16_t numEntries;
uint8_t version;
uint8_t entryBytes;
};
struct Clause22Message {
uint8_t phyAddr; //5 bits
uint8_t page; //8 bits
uint16_t regAddr; //5 bits
uint16_t regVal;
}; //6 bytes
struct Clause45Message {
uint8_t port; //5 bits
uint8_t device; //5 bits
uint16_t regAddr;
uint16_t regVal;
}; //6 bytes
struct PhyRegisterPacket_t {
union {
struct {
uint16_t Enabled : 1;
uint16_t WriteEnable : 1;
uint16_t Clause45Enable : 1;
uint16_t reserved : 9;
uint16_t version : 4;
};
uint16_t flags;
};
union {
Clause22Message clause22;
Clause45Message clause45;
};
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#pragma pack(pop)
static constexpr size_t MaxPhyEntries = 128u;
static constexpr size_t MaxBytesPhyEntries = MaxPhyEntries * sizeof(PhyRegisterHeader_t);
static constexpr uint8_t PhyPacketVersion = 1u;
static constexpr uint8_t FiveBits = 0x1Fu;
class EthPhyMessage;
struct HardwareEthernetPhyRegisterPacket {
static std::shared_ptr<EthPhyMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
static bool EncodeFromMessage(const EthPhyMessage& message, std::vector<uint8_t>& bytestream, const device_eventhandler_t& report);
};
}
#endif //__cplusplus
#endif

View File

@ -0,0 +1,28 @@
#ifndef __LOGICALDISKINFOPACKET_H__
#define __LOGICALDISKINFOPACKET_H__
#ifdef __cplusplus
#include "icsneo/communication/message/logicaldiskinfomessage.h"
#include "icsneo/api/eventmanager.h"
#include <cstdint>
#include <memory>
namespace icsneo {
#pragma pack(push,2)
struct LogicalDiskInfoPacket {
static std::shared_ptr<LogicalDiskInfoMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
uint16_t isConnected;
uint32_t numSectors;
uint32_t hiddenSectors;
uint32_t bytesPerSector;
};
#pragma pack(pop)
}
#endif // __cplusplus
#endif

View File

@ -23,7 +23,7 @@ public:
std::vector<std::shared_ptr<Packet>> output(); std::vector<std::shared_ptr<Packet>> output();
bool disableChecksum = false; // Even for short packets bool disableChecksum = false; // Even for short packets
bool align16bit = true; // Not needed for Gigalog, Galaxy, etc and newer bool align16bit = true; // Not needed for Mars, Galaxy, etc and newer
private: private:
enum class ReadState { enum class ReadState {

View File

@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <cstring> #include <cstring>
#include <cstdint>
#include <atomic> #include <atomic>
#include <type_traits> #include <type_traits>
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
@ -16,6 +17,10 @@
#include "icsneo/device/nullsettings.h" #include "icsneo/device/nullsettings.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/device/deviceversion.h" #include "icsneo/device/deviceversion.h"
#include "icsneo/device/founddevice.h"
#include "icsneo/disk/diskreaddriver.h"
#include "icsneo/disk/diskwritedriver.h"
#include "icsneo/disk/nulldiskdriver.h"
#include "icsneo/communication/communication.h" #include "icsneo/communication/communication.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/communication/encoder.h" #include "icsneo/communication/encoder.h"
@ -24,10 +29,25 @@
#include "icsneo/communication/message/resetstatusmessage.h" #include "icsneo/communication/message/resetstatusmessage.h"
#include "icsneo/device/extensions/flexray/controller.h" #include "icsneo/device/extensions/flexray/controller.h"
#include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h" #include "icsneo/communication/message/flexray/control/flexraycontrolmessage.h"
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/third-party/concurrentqueue/concurrentqueue.h" #include "icsneo/third-party/concurrentqueue/concurrentqueue.h"
#include "icsneo/platform/optional.h" #include "icsneo/platform/optional.h"
#include "icsneo/platform/nodiscard.h" #include "icsneo/platform/nodiscard.h"
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
static constexpr DeviceType::Enum DEVICE_TYPE = type; \
className(const FoundDevice& dev) : className(neodevice_t(dev, DEVICE_TYPE), dev.makeDriver) {}
// Devices which are discernable by the first two characters of their serial
#define ICSNEO_FINDABLE_DEVICE(className, type, serialStart) \
static constexpr const char* SERIAL_START = serialStart; \
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
// Devices which are discernable by their USB PID
#define ICSNEO_FINDABLE_DEVICE_BY_PID(className, type, pid) \
static constexpr const uint16_t PRODUCT_ID = pid; \
ICSNEO_FINDABLE_DEVICE_BASE(className, type)
namespace icsneo { namespace icsneo {
class DeviceExtension; class DeviceExtension;
@ -42,7 +62,6 @@ public:
uint16_t getTimestampResolution() const; uint16_t getTimestampResolution() const;
DeviceType getType() const { return DeviceType(data.type); } DeviceType getType() const { return DeviceType(data.type); }
uint16_t getProductId() const { return productId; }
std::string getSerial() const { return data.serial; } std::string getSerial() const { return data.serial; }
uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); } uint32_t getSerialNumber() const { return Device::SerialStringToNum(getSerial()); }
const neodevice_t& getNeoDevice() const { return data; } const neodevice_t& getNeoDevice() const { return data; }
@ -121,8 +140,8 @@ public:
int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); } int addMessageCallback(const MessageCallback& cb) { return com->addMessageCallback(cb); }
bool removeMessageCallback(int id) { return com->removeMessageCallback(id); } bool removeMessageCallback(int id) { return com->removeMessageCallback(id); }
bool transmit(std::shared_ptr<Message> message); bool transmit(std::shared_ptr<Frame> frame);
bool transmit(std::vector<std::shared_ptr<Message>> messages); bool transmit(std::vector<std::shared_ptr<Frame>> frames);
void setWriteBlocks(bool blocks); void setWriteBlocks(bool blocks);
@ -138,6 +157,74 @@ public:
virtual size_t getNetworkCountByType(Network::Type) const; virtual size_t getNetworkCountByType(Network::Type) const;
virtual Network getNetworkByNumber(Network::Type, size_t) const; virtual Network getNetworkByNumber(Network::Type, size_t) const;
/**
* Read from the logical disk in this device, starting from byte `pos`
* and reading up to `amount` bytes.
*
* The number of bytes read will be returned in case of success.
*
* If the number of bytes read is less than the amount requested,
* an error will be set in icsneo::GetLastError() explaining why.
* Likely, either the end of the logical disk has been reached, or
* the timeout was reached while the read had only partially completed.
*
* Upon failure, icsneo::nullopt will be returned and an error will be
* set in icsneo::GetLastError().
*/
optional<uint64_t> readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount,
std::chrono::milliseconds timeout = Disk::DefaultTimeout);
/**
* Write to the logical disk in this device, starting from byte `pos`
* and writing up to `amount` bytes.
*
* The number of bytes written will be returned in case of success.
*
* If the number of bytes written is less than the amount requested,
* an error will be set in icsneo::GetLastError() explaining why.
* Likely, either the end of the logical disk has been reached, or
* the timeout was reached while the write had only partially completed.
*
* Upon failure, icsneo::nullopt will be returned and an error will be
* set in icsneo::GetLastError().
*/
optional<uint64_t> writeLogicalDisk(uint64_t pos, const uint8_t* from, uint64_t amount,
std::chrono::milliseconds timeout = Disk::DefaultTimeout);
/**
* Check if the logical disk is connected. This means the disk is inserted,
* and if required (for instance for multi-card configurations), configured
* properly.
*
* This method is synchronous and contacts the device for the latest status.
*
* `icsneo::nullopt` will be returned if the device does not respond in a
* timely manner.
*/
optional<bool> isLogicalDiskConnected();
/**
* Get the size of the connected logical disk in bytes.
*
* This method is synchronous and contacts the device for the latest status.
*
* `icsneo::nullopt` will be returned if the device does not respond in a
* timely manner, or if the disk is disconnected/improperly configured.
*/
optional<uint64_t> getLogicalDiskSize();
/**
* Get the offset to the VSA filesystem within the logical disk, represented
* in bytes.
*
* This method is synchronous and consacts the device for the latest status
* if necessary.
*
* `icsneo::nullopt` will be returned if the device does not respond in a
* timely manner, or if the disk is disconnected/improperly configured.
*/
optional<uint64_t> getVSAOffsetInLogicalDisk();
/** /**
* Retrieve the number of Ethernet (DoIP) Activation lines present * Retrieve the number of Ethernet (DoIP) Activation lines present
* on this device. * on this device.
@ -224,11 +311,18 @@ public:
const device_eventhandler_t& getEventHandler() const { return report; } const device_eventhandler_t& getEventHandler() const { return report; }
/**
* Tell whether the current device supports reading and writing
* Ethernet PHY registers through MDIO.
*/
virtual bool getEthPhyRegControlSupported() const { return false; }
optional<EthPhyMessage> sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout = std::chrono::milliseconds(50));
std::shared_ptr<Communication> com; std::shared_ptr<Communication> com;
std::unique_ptr<IDeviceSettings> settings; std::unique_ptr<IDeviceSettings> settings;
protected: protected:
uint16_t productId = 0;
bool online = false; bool online = false;
int messagePollingCallbackID = 0; int messagePollingCallbackID = 0;
int internalHandlerCallbackID = 0; int internalHandlerCallbackID = 0;
@ -243,24 +337,28 @@ protected:
std::array<optional<double>, 2> miscAnalog; std::array<optional<double>, 2> miscAnalog;
// START Initialization Functions // START Initialization Functions
Device(neodevice_t neodevice = { 0 }) { Device(neodevice_t neodevice) : data(neodevice) {
data = neodevice;
data.device = this; data.device = this;
} }
template<typename Driver, typename Settings = NullSettings> template<typename Settings = NullSettings, typename DiskRead = Disk::NullDriver, typename DiskWrite = Disk::NullDriver>
void initialize() { void initialize(const driver_factory_t& makeDriver) {
report = makeEventHandler(); report = makeEventHandler();
auto driver = makeDriver<Driver>();
setupDriver(*driver);
auto encoder = makeEncoder(); auto encoder = makeEncoder();
setupEncoder(*encoder); setupEncoder(*encoder);
auto decoder = makeDecoder(); auto decoder = makeDecoder();
setupDecoder(*decoder); setupDecoder(*decoder);
com = makeCommunication(std::move(driver), std::bind(&Device::makeConfiguredPacketizer, this), std::move(encoder), std::move(decoder)); com = makeCommunication(
makeDriver(report, getWritableNeoDevice()),
std::bind(&Device::makeConfiguredPacketizer, this),
std::move(encoder),
std::move(decoder)
);
setupCommunication(*com); setupCommunication(*com);
settings = makeSettings<Settings>(com); settings = makeSettings<Settings>(com);
setupSettings(*settings); setupSettings(*settings);
diskReadDriver = std::unique_ptr<DiskRead>(new DiskRead());
diskWriteDriver = std::unique_ptr<DiskWrite>(new DiskWrite());
setupSupportedRXNetworks(supportedRXNetworks); setupSupportedRXNetworks(supportedRXNetworks);
setupSupportedTXNetworks(supportedTXNetworks); setupSupportedTXNetworks(supportedTXNetworks);
setupExtensions(); setupExtensions();
@ -272,10 +370,6 @@ protected:
}; };
} }
template<typename Driver>
std::unique_ptr<Driver> makeDriver() { return std::unique_ptr<Driver>(new Driver(report, getWritableNeoDevice())); }
virtual void setupDriver(Driver&) {}
virtual std::unique_ptr<Packetizer> makePacketizer() { return std::unique_ptr<Packetizer>(new Packetizer(report)); } virtual std::unique_ptr<Packetizer> makePacketizer() { return std::unique_ptr<Packetizer>(new Packetizer(report)); }
virtual void setupPacketizer(Packetizer&) {} virtual void setupPacketizer(Packetizer&) {}
std::unique_ptr<Packetizer> makeConfiguredPacketizer() { std::unique_ptr<Packetizer> makeConfiguredPacketizer() {
@ -295,7 +389,9 @@ protected:
std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer, std::function<std::unique_ptr<Packetizer>()> makeConfiguredPacketizer,
std::unique_ptr<Encoder> e, std::unique_ptr<Encoder> e,
std::unique_ptr<Decoder> d) { return std::make_shared<Communication>(report, std::move(t), makeConfiguredPacketizer, std::move(e), std::move(d)); } std::unique_ptr<Decoder> d) { return std::make_shared<Communication>(report, std::move(t), makeConfiguredPacketizer, std::move(e), std::move(d)); }
virtual void setupCommunication(Communication&) {} virtual void setupCommunication(Communication& communication) {
communication.packetizer = communication.makeConfiguredPacketizer();
}
template<typename Settings> template<typename Settings>
std::unique_ptr<IDeviceSettings> makeSettings(std::shared_ptr<Communication> com) { std::unique_ptr<IDeviceSettings> makeSettings(std::shared_ptr<Communication> com) {
@ -328,7 +424,7 @@ protected:
void handleInternalMessage(std::shared_ptr<Message> message); void handleInternalMessage(std::shared_ptr<Message> message);
virtual void handleDeviceStatus(const std::shared_ptr<Message>&) {} virtual void handleDeviceStatus(const std::shared_ptr<RawMessage>&) {}
neodevice_t& getWritableNeoDevice() { return data; } neodevice_t& getWritableNeoDevice() { return data; }
@ -337,6 +433,10 @@ private:
std::shared_ptr<ResetStatusMessage> latestResetStatus; std::shared_ptr<ResetStatusMessage> latestResetStatus;
std::vector<optional<DeviceAppVersion>> versions; std::vector<optional<DeviceAppVersion>> versions;
mutable std::mutex diskLock;
std::unique_ptr<Disk::ReadDriver> diskReadDriver;
std::unique_ptr<Disk::WriteDriver> diskWriteDriver;
mutable std::mutex extensionsLock; mutable std::mutex extensionsLock;
std::vector<std::shared_ptr<DeviceExtension>> extensions; std::vector<std::shared_ptr<DeviceExtension>> extensions;
void forEachExtension(std::function<bool(const std::shared_ptr<DeviceExtension>&)> fn); void forEachExtension(std::function<bool(const std::shared_ptr<DeviceExtension>&)> fn);
@ -369,6 +469,7 @@ private:
void enforcePollingMessageLimit(); void enforcePollingMessageLimit();
std::atomic<bool> stopHeartbeatThread{false}; std::atomic<bool> stopHeartbeatThread{false};
std::mutex heartbeatMutex;
std::thread heartbeatThread; std::thread heartbeatThread;
}; };

View File

@ -29,7 +29,7 @@ public:
RADSupermoon = (0x00000003), RADSupermoon = (0x00000003),
DW_VCAN = (0x00000004), DW_VCAN = (0x00000004),
RADMoon2 = (0x00000005), RADMoon2 = (0x00000005),
RADGigalog = (0x00000006), RADMars = (0x00000006),
VCAN4_1 = (0x00000007), VCAN4_1 = (0x00000007),
FIRE = (0x00000008), FIRE = (0x00000008),
RADPluto = (0x00000009), RADPluto = (0x00000009),
@ -95,8 +95,8 @@ public:
return "DW_VCAN"; return "DW_VCAN";
case RADMoon2: case RADMoon2:
return "RAD-Moon 2"; return "RAD-Moon 2";
case RADGigalog: case RADMars:
return "RAD-Gigalog"; return "RAD-Mars";
case VCAN4_1: case VCAN4_1:
return "ValueCAN 4-1"; return "ValueCAN 4-1";
case FIRE: case FIRE:
@ -203,7 +203,7 @@ private:
#define ICSNEO_DEVICETYPE_RADSUPERMOON ((devicetype_t)0x00000003) #define ICSNEO_DEVICETYPE_RADSUPERMOON ((devicetype_t)0x00000003)
#define ICSNEO_DEVICETYPE_DW_VCAN ((devicetype_t)0x00000004) #define ICSNEO_DEVICETYPE_DW_VCAN ((devicetype_t)0x00000004)
#define ICSNEO_DEVICETYPE_RADMOON2 ((devicetype_t)0x00000005) #define ICSNEO_DEVICETYPE_RADMOON2 ((devicetype_t)0x00000005)
#define ICSNEO_DEVICETYPE_RADGIGALOG ((devicetype_t)0x00000006) #define ICSNEO_DEVICETYPE_RADMARS ((devicetype_t)0x00000006)
#define ICSNEO_DEVICETYPE_VCAN4_1 ((devicetype_t)0x00000007) #define ICSNEO_DEVICETYPE_VCAN4_1 ((devicetype_t)0x00000007)
#define ICSNEO_DEVICETYPE_FIRE ((devicetype_t)0x00000008) #define ICSNEO_DEVICETYPE_FIRE ((devicetype_t)0x00000008)
#define ICSNEO_DEVICETYPE_RADPLUTO ((devicetype_t)0x00000009) #define ICSNEO_DEVICETYPE_RADPLUTO ((devicetype_t)0x00000009)

View File

@ -7,7 +7,8 @@
namespace icsneo { namespace icsneo {
static void AddBuiltInExtensionsTo([[maybe_unused]] const std::shared_ptr<icsneo::Device>& device) { static void AddBuiltInExtensionsTo(const std::shared_ptr<icsneo::Device>& device) {
(void)device; // [[maybe_unused]]
@LIBICSNEO_EXT_CODE@ @LIBICSNEO_EXT_CODE@
} }

View File

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

View File

@ -108,6 +108,7 @@ private:
bool startWhenGoingOnline = false; bool startWhenGoingOnline = false;
bool allowColdstart = false; bool allowColdstart = false;
bool wakeupBeforeStart = false; bool wakeupBeforeStart = false;
bool lastSeenRunning = false;
public: public:
#define neoflexray_controller_config_t icsneo::FlexRay::Controller::Configuration #define neoflexray_controller_config_t icsneo::FlexRay::Controller::Configuration

View File

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

View File

@ -0,0 +1,21 @@
#ifndef __FOUNDDEVICE_H_
#define __FOUNDDEVICE_H_
#include "icsneo/communication/driver.h"
#include "icsneo/device/neodevice.h"
namespace icsneo {
typedef std::function< std::unique_ptr<Driver>(device_eventhandler_t err, neodevice_t& forDevice) > driver_factory_t;
class FoundDevice {
public:
neodevice_handle_t handle = 0;
char serial[7] = {};
uint16_t productId = 0;
driver_factory_t makeDriver;
};
} // namespace icsneo
#endif // __FOUNDDEVICE_H_

View File

@ -384,6 +384,26 @@ typedef struct LOGGER_SETTINGS_t
} LOGGER_SETTINGS; } LOGGER_SETTINGS;
#define LOGGER_SETTINGS_SIZE 4 #define LOGGER_SETTINGS_SIZE 4
#define RAD_GPTP_NUM_PORTS 1 // 1 because only supported as gPTP endpoint
typedef struct RAD_GPTP_SETTINGS_t
{
uint32_t neighborPropDelayThresh;//ns
uint32_t sys_phc_sync_interval;//ns
int8_t logPDelayReqInterval;// log2ms
int8_t logSyncInterval;// log2ms
int8_t logAnnounceInterval;// log2ms
uint8_t profile;
uint8_t priority1;
uint8_t clockclass;
uint8_t clockaccuracy;
uint8_t priority2;
uint16_t offset_scaled_log_variance;
uint8_t gPTPportRole[RAD_GPTP_NUM_PORTS];
uint8_t portEnable[RAD_GPTP_NUM_PORTS];
uint8_t rsvd[16];
} RAD_GPTP_SETTINGS;//36 Bytes with RAD_GPTP_NUM_PORTS = 1
#define RAD_GPTP_SETTINGS_SIZE 36
#define RAD_REPORTING_SETTINGS_FLAG_TEMP_ENABLE 0x00000001 #define RAD_REPORTING_SETTINGS_FLAG_TEMP_ENABLE 0x00000001
#define RAD_REPORTING_SETTINGS_FLAG_MIC2_GPS_ENABLE 0x00000002 // USB port 1 #define RAD_REPORTING_SETTINGS_FLAG_MIC2_GPS_ENABLE 0x00000002 // USB port 1
#define RAD_REPORTING_SETTINGS_FLAG_INT_GPS_ENABLE 0x00000004 #define RAD_REPORTING_SETTINGS_FLAG_INT_GPS_ENABLE 0x00000004

View File

@ -9,6 +9,7 @@
namespace icsneo { namespace icsneo {
class Device; class Device;
class FoundDevice;
} }
typedef icsneo::Device* devicehandle_t; typedef icsneo::Device* devicehandle_t;
@ -20,7 +21,13 @@ typedef int32_t neodevice_handle_t;
#pragma pack(push, 1) #pragma pack(push, 1)
#ifdef __cplusplus
typedef struct neodevice_t {
neodevice_t();
neodevice_t(const icsneo::FoundDevice& found, devicetype_t inType);
#else
typedef struct { typedef struct {
#endif
devicehandle_t device; // Pointer back to the C++ device object devicehandle_t device; // Pointer back to the C++ device object
neodevice_handle_t handle; // Handle for use by the underlying driver neodevice_handle_t handle; // Handle for use by the underlying driver
devicetype_t type; devicetype_t type;

View File

@ -7,7 +7,6 @@
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/communication/decoder.h" #include "icsneo/communication/decoder.h"
#include "icsneo/platform/cdcacm.h"
#include "icsneo/device/tree/etherbadge/etherbadgesettings.h" #include "icsneo/device/tree/etherbadge/etherbadgesettings.h"
namespace icsneo { namespace icsneo {
@ -15,49 +14,35 @@ namespace icsneo {
class EtherBADGE : public Device { class EtherBADGE : public Device {
public: public:
// Serial numbers start with EB // Serial numbers start with EB
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::EtherBADGE; // USB PID is 0x1107, standard driver is CDCACM
static constexpr const uint16_t PRODUCT_ID = 0x1107; ICSNEO_FINDABLE_DEVICE(EtherBADGE, DeviceType::EtherBADGE, "EB");
static constexpr const char* SERIAL_START = "EB";
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
found.emplace_back(new EtherBADGE(neodevice));
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
Network::NetID::HSCAN, Network::NetID::HSCAN,
Network::NetID::LIN, Network::NetID::LIN,
Network::NetID::OP_Ethernet1 Network::NetID::OP_Ethernet1
}; };
return supportedNetworks; return supportedNetworks;
} }
EtherBADGE(neodevice_t neodevice) : Device(neodevice) { protected:
getWritableNeoDevice().type = DEVICE_TYPE; EtherBADGE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
productId = PRODUCT_ID; initialize<EtherBADGESettings>(makeDriver);
initialize<CDCACM, EtherBADGESettings>();
} }
protected:
virtual void setupEncoder(Encoder& encoder) override { virtual void setupEncoder(Encoder& encoder) override {
Device::setupEncoder(encoder); Device::setupEncoder(encoder);
encoder.supportCANFD = true; encoder.supportCANFD = true;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
bool requiresVehiclePower() const override { return false; } bool requiresVehiclePower() const override { return false; }
}; };

View File

@ -5,23 +5,14 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/cdcacm.h"
namespace icsneo { namespace icsneo {
class NeoOBD2PRO : public Device { class NeoOBD2PRO : public Device {
public: public:
// Serial numbers are NP**** // Serial numbers start with NP
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::OBD2_PRO; // USB PID is 0x1103, standard driver is CDCACM
static constexpr const uint16_t PRODUCT_ID = 0x1103; ICSNEO_FINDABLE_DEVICE(NeoOBD2PRO, DeviceType::OBD2_PRO, "NP");
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
found.emplace_back(new NeoOBD2PRO(neodevice));
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
@ -32,19 +23,17 @@ public:
} }
private: private:
NeoOBD2PRO(neodevice_t neodevice) : Device(neodevice) { NeoOBD2PRO(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<CDCACM>(); initialize(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
bool requiresVehiclePower() const override { return false; } bool requiresVehiclePower() const override { return false; }
}; };

View File

@ -5,23 +5,14 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/cdcacm.h"
namespace icsneo { namespace icsneo {
class NeoOBD2SIM : public Device { class NeoOBD2SIM : public Device {
public: public:
// Serial numbers are OS**** // Serial numbers start with OS
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::OBD2_SIM; // USB PID is 0x1100, standard driver is CDCACM
static constexpr const uint16_t PRODUCT_ID = 0x1100; ICSNEO_FINDABLE_DEVICE(NeoOBD2SIM, DeviceType::OBD2_SIM, "OS");
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
found.emplace_back(new NeoOBD2SIM(neodevice));
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
@ -32,19 +23,17 @@ public:
} }
private: private:
NeoOBD2SIM(neodevice_t neodevice) : Device(neodevice) { NeoOBD2SIM(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<CDCACM>(); initialize(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
bool requiresVehiclePower() const override { return false; } bool requiresVehiclePower() const override { return false; }
}; };

View File

@ -5,23 +5,14 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/tree/neovifire/neovifiresettings.h" #include "icsneo/device/tree/neovifire/neovifiresettings.h"
namespace icsneo { namespace icsneo {
class NeoVIFIRE : public Device { class NeoVIFIRE : public Device {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::FIRE; // USB PID is 0x0701, standard driver is FTDI
static constexpr const uint16_t PRODUCT_ID = 0x0701; ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIFIRE, DeviceType::FIRE, 0x0701);
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
found.emplace_back(new NeoVIFIRE(neodevice)); // Creation of the shared_ptr
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
@ -67,19 +58,17 @@ public:
} }
private: private:
NeoVIFIRE(neodevice_t neodevice) : Device(neodevice) { NeoVIFIRE(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<FTDI, NeoVIFIRESettings>(); initialize<NeoVIFIRESettings>(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
}; };
} }

View File

@ -5,15 +5,16 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/tree/neovifire2/neovifire2settings.h" #include "icsneo/device/tree/neovifire2/neovifire2settings.h"
namespace icsneo { namespace icsneo {
class NeoVIFIRE2 : public Device { class NeoVIFIRE2 : public Device {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::FIRE2; // Serial numbers start with CY
static constexpr const char* SERIAL_START = "CY"; // USB PID is 0x1000, standard driver is FTDI
// Ethernet MAC allocation is 0x04, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(NeoVIFIRE2, DeviceType::FIRE2, "CY");
enum class SKU { enum class SKU {
Standard, Standard,
@ -87,8 +88,22 @@ public:
} }
protected: protected:
NeoVIFIRE2(neodevice_t neodevice) : Device(neodevice) { NeoVIFIRE2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
getWritableNeoDevice().type = DEVICE_TYPE; initialize<NeoVIFIRE2Settings>(makeDriver);
}
void setupSettings(IDeviceSettings& ssettings) override {
if(com->driver->isEthernet()) {
// TODO Check firmware version, old firmwares will reset Ethernet settings on settings send
ssettings.readonly = true;
}
}
bool currentDriverSupportsDFU() const override { return com->driver->isEthernet(); }
void setupPacketizer(Packetizer& packetizer) override {
Device::setupPacketizer(packetizer);
packetizer.align16bit = !com->driver->isEthernet();
} }
virtual void setupEncoder(Encoder& encoder) override { virtual void setupEncoder(Encoder& encoder) override {
@ -96,16 +111,16 @@ protected:
encoder.supportCANFD = true; encoder.supportCANFD = true;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(neovifire2_status_t)) if(message->data.size() < sizeof(neovifire2_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const neovifire2_status_t* status = reinterpret_cast<const neovifire2_status_t*>(message->data.data()); const neovifire2_status_t* status = reinterpret_cast<const neovifire2_status_t*>(message->data.data());

View File

@ -1,66 +0,0 @@
#ifndef __NEOVIFIRE2ETH_H_
#define __NEOVIFIRE2ETH_H_
#ifdef __cplusplus
#include "icsneo/device/tree/neovifire2/neovifire2.h"
#include "icsneo/platform/pcap.h"
#include <memory>
namespace icsneo {
class NeoVIFIRE2ETH : public NeoVIFIRE2 {
public:
static constexpr const uint16_t PRODUCT_ID = 0x0004;
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
std::vector<std::shared_ptr<Device>> found;
for(auto& foundDev : pcapDevices) {
auto fakedev = std::shared_ptr<NeoVIFIRE2ETH>(new NeoVIFIRE2ETH({}));
for (auto& payload : foundDev.discoveryPackets)
fakedev->com->packetizer->input(payload);
for (auto& packet : fakedev->com->packetizer->output()) {
std::shared_ptr<Message> msg;
if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn)
continue; // Not a serial number message
if(sn->deviceSerial.length() < 2)
continue;
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
continue; // Not a FIRE 2
auto device = foundDev.device;
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
found.push_back(std::make_shared<NeoVIFIRE2ETH>(std::move(device)));
break;
}
}
return found;
}
NeoVIFIRE2ETH(neodevice_t neodevice) : NeoVIFIRE2(neodevice) {
initialize<PCAP, NeoVIFIRE2Settings>();
productId = PRODUCT_ID;
}
bool currentDriverSupportsDFU() const override { return false; }
protected:
void setupSettings(IDeviceSettings& ssettings) override {
// TODO Check firmware version, old firmwares will reset Ethernet settings on settings send
ssettings.readonly = true;
}
};
}
#endif // __cplusplus
#endif

View File

@ -1,34 +0,0 @@
#ifndef __NEOVIFIRE2USB_H_
#define __NEOVIFIRE2USB_H_
#ifdef __cplusplus
#include "icsneo/device/tree/neovifire2/neovifire2.h"
#include "icsneo/platform/ftdi.h"
namespace icsneo {
class NeoVIFIRE2USB : public NeoVIFIRE2 {
public:
static constexpr const uint16_t PRODUCT_ID = 0x1000;
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
found.emplace_back(new NeoVIFIRE2USB(neodevice)); // Creation of the shared_ptr
return found;
}
private:
NeoVIFIRE2USB(neodevice_t neodevice) : NeoVIFIRE2(neodevice) {
initialize<FTDI, NeoVIFIRE2Settings>();
productId = PRODUCT_ID;
}
};
}
#endif // __cplusplus
#endif

View File

@ -3,48 +3,17 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/pcap.h" #include "icsneo/disk/extextractordiskreaddriver.h"
#include "icsneo/disk/neomemorydiskdriver.h"
#include "icsneo/device/tree/neovired2/neovired2settings.h" #include "icsneo/device/tree/neovired2/neovired2settings.h"
namespace icsneo { namespace icsneo {
class NeoVIRED2 : public Device { class NeoVIRED2 : public Device {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RED2; // Serial numbers start with D2
static constexpr const char* SERIAL_START = "D2"; // Ethernet MAC allocation is 0x0E, standard driver is Raw
static constexpr const uint16_t PRODUCT_ID = 0x000E; ICSNEO_FINDABLE_DEVICE(NeoVIRED2, DeviceType::RED2, "D2");
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
std::vector<std::shared_ptr<Device>> found;
for(auto& foundDev : pcapDevices) {
auto fakedev = std::shared_ptr<NeoVIRED2>(new NeoVIRED2({}));
for (auto& payload : foundDev.discoveryPackets)
fakedev->com->packetizer->input(payload);
for (auto& packet : fakedev->com->packetizer->output()) {
std::shared_ptr<Message> msg;
if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn)
continue; // Not a serial number message
if(sn->deviceSerial.length() < 2)
continue;
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
continue; // Not a RED 2
auto device = foundDev.device;
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
found.emplace_back(new NeoVIRED2(std::move(device)));
break;
}
}
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
@ -66,10 +35,8 @@ public:
} }
protected: protected:
NeoVIRED2(neodevice_t neodevice) : Device(neodevice) { NeoVIRED2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<PCAP, NeoVIRED2Settings>(); initialize<NeoVIRED2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual void setupEncoder(Encoder& encoder) override { virtual void setupEncoder(Encoder& encoder) override {
@ -77,13 +44,18 @@ protected:
encoder.supportCANFD = true; encoder.supportCANFD = true;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupPacketizer(Packetizer& packetizer) override {
Device::setupPacketizer(packetizer);
packetizer.align16bit = false;
}
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
}; };
} }

View File

@ -10,6 +10,11 @@ namespace icsneo {
#endif #endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nameless struct/union
#endif
#pragma pack(push, 2) #pragma pack(push, 2)
typedef struct { typedef struct {
uint16_t perf_en; uint16_t perf_en;
@ -57,8 +62,7 @@ typedef struct {
ETHERNET_SETTINGS ethernet; ETHERNET_SETTINGS ethernet;
TIMESYNC_ICSHARDWARE_SETTINGS timeSync; TIMESYNC_ICSHARDWARE_SETTINGS timeSync;
STextAPISettings text_api; STextAPISettings text_api;
struct struct {
{
uint32_t disableUsbCheckOnBoot : 1; uint32_t disableUsbCheckOnBoot : 1;
uint32_t enableLatencyTest : 1; uint32_t enableLatencyTest : 1;
uint32_t busMessagesToAndroid : 1; uint32_t busMessagesToAndroid : 1;
@ -87,6 +91,10 @@ typedef struct {
} neovired2_status_t; } neovired2_status_t;
#pragma pack(pop) #pragma pack(pop)
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#ifdef __cplusplus #ifdef __cplusplus
#include <iostream> #include <iostream>

View File

@ -5,28 +5,19 @@
#include "icsneo/device/tree/plasion/plasion.h" #include "icsneo/device/tree/plasion/plasion.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h" #include "icsneo/disk/plasiondiskreaddriver.h"
#include "icsneo/disk/neomemorydiskdriver.h"
namespace icsneo { namespace icsneo {
class NeoVIION : public Plasion { class NeoVIION : public Plasion {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::ION; // USB PID is 0x0901, standard driver is FTDI
static constexpr const uint16_t PRODUCT_ID = 0x0901; ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIION, DeviceType::ION, 0x0901);
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
found.emplace_back(new NeoVIION(neodevice));
return found;
}
private: private:
NeoVIION(neodevice_t neodevice) : Plasion(neodevice) { NeoVIION(neodevice_t neodevice, const driver_factory_t& makeDriver) : Plasion(neodevice) {
initialize<FTDI>(); initialize<NullSettings, Disk::PlasionDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual std::shared_ptr<Communication> makeCommunication( virtual std::shared_ptr<Communication> makeCommunication(

View File

@ -5,28 +5,17 @@
#include "icsneo/device/tree/plasion/plasion.h" #include "icsneo/device/tree/plasion/plasion.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/ftdi.h"
namespace icsneo { namespace icsneo {
class NeoVIPLASMA : public Plasion { class NeoVIPLASMA : public Plasion {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::PLASMA; // USB PID is 0x0801, standard driver is FTDI
static constexpr const uint16_t PRODUCT_ID = 0x0801; ICSNEO_FINDABLE_DEVICE_BY_PID(NeoVIPLASMA, DeviceType::PLASMA, 0x0801);
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : FTDI::FindByProduct(PRODUCT_ID))
found.emplace_back(new NeoVIPLASMA(neodevice));
return found;
}
private: private:
NeoVIPLASMA(neodevice_t neodevice) : Plasion(neodevice) { NeoVIPLASMA(neodevice_t neodevice, const driver_factory_t& makeDriver) : Plasion(neodevice) {
initialize<FTDI>(); initialize<NullSettings, Disk::PlasionDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual std::shared_ptr<Communication> makeCommunication( virtual std::shared_ptr<Communication> makeCommunication(

View File

@ -5,7 +5,6 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/communication/multichannelcommunication.h" #include "icsneo/communication/multichannelcommunication.h"
#include "icsneo/platform/ftdi.h"
#include "icsneo/device/extensions/flexray/extension.h" #include "icsneo/device/extensions/flexray/extension.h"
namespace icsneo { namespace icsneo {
@ -45,6 +44,8 @@ public:
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
protected: protected:
using Device::Device;
// TODO This is done so that Plasion can still transmit it's basic networks, awaiting slave VNET support // TODO This is done so that Plasion can still transmit it's basic networks, awaiting slave VNET support
virtual bool isSupportedRXNetwork(const Network&) const override { return true; } virtual bool isSupportedRXNetwork(const Network&) const override { return true; }
virtual bool isSupportedTXNetwork(const Network&) const override { return true; } virtual bool isSupportedTXNetwork(const Network&) const override { return true; }
@ -55,7 +56,7 @@ protected:
addExtension(std::make_shared<FlexRay::Extension>(*this, flexRayControllers)); addExtension(std::make_shared<FlexRay::Extension>(*this, flexRayControllers));
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
// TODO Check configuration for FlexRay ColdStart mode, disable FlexRay 2 if so // TODO Check configuration for FlexRay ColdStart mode, disable FlexRay 2 if so
@ -80,16 +81,13 @@ protected:
return ret; return ret;
} }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(fire2vnet_status_t)) if(message->data.size() < sizeof(fire2vnet_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const fire2vnet_status_t* status = reinterpret_cast<const fire2vnet_status_t*>(message->data.data()); const fire2vnet_status_t* status = reinterpret_cast<const fire2vnet_status_t*>(message->data.data());
ethActivationStatus = status->ethernetActivationLineEnabled; ethActivationStatus = status->ethernetActivationLineEnabled;
} }
public:
Plasion(neodevice_t neodevice) : Device(neodevice) {}
}; };
} }

View File

@ -3,23 +3,14 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/cdcacm.h"
namespace icsneo { namespace icsneo {
class RADEpsilon : public Device { class RADEpsilon : public Device {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADEpsilon; // Serial numbers start with RE
static constexpr const char* SERIAL_START = "RE"; // USB PID is 0x1109, standard driver is CDCACM
static constexpr const uint16_t PRODUCT_ID = 0x1109; ICSNEO_FINDABLE_DEVICE(RADEpsilon, DeviceType::RADEpsilon, "RE");
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : CDCACM::FindByProduct(PRODUCT_ID))
found.emplace_back(new RADEpsilon(neodevice));
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
@ -34,10 +25,8 @@ public:
} }
protected: protected:
RADEpsilon(neodevice_t neodevice) : Device(neodevice) { RADEpsilon(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<CDCACM>(); initialize(makeDriver);
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
} }
virtual void setupEncoder(Encoder& encoder) override { virtual void setupEncoder(Encoder& encoder) override {
@ -45,13 +34,13 @@ protected:
encoder.supportCANFD = true; encoder.supportCANFD = true;
} }
virtual void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
for(auto& netid : GetSupportedNetworks()) for(auto& netid : GetSupportedNetworks())
rxNetworks.emplace_back(netid); rxNetworks.emplace_back(netid);
} }
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
virtual void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
}; };
} }

View File

@ -5,7 +5,6 @@
#include "icsneo/device/device.h" #include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h" #include "icsneo/device/devicetype.h"
#include "icsneo/platform/pcap.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/communication/decoder.h" #include "icsneo/communication/decoder.h"
#include "icsneo/device/tree/radgalaxy/radgalaxysettings.h" #include "icsneo/device/tree/radgalaxy/radgalaxysettings.h"
@ -15,41 +14,8 @@ namespace icsneo {
class RADGalaxy : public Device { class RADGalaxy : public Device {
public: public:
// Serial numbers start with RG // Serial numbers start with RG
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGalaxy; // Ethernet MAC allocation is 0x03, standard driver is Raw
static constexpr const uint16_t PRODUCT_ID = 0x0003; ICSNEO_FINDABLE_DEVICE(RADGalaxy, DeviceType::RADGalaxy, "RG");
static constexpr const char* SERIAL_START = "RG";
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
std::vector<std::shared_ptr<Device>> found;
for(auto& foundDev : pcapDevices) {
auto fakedev = std::shared_ptr<RADGalaxy>(new RADGalaxy({}));
for(auto& payload : foundDev.discoveryPackets)
fakedev->com->packetizer->input(payload);
for(auto& packet : fakedev->com->packetizer->output()) {
std::shared_ptr<Message> msg;
if(!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn)
continue; // Not a serial number message
if(sn->deviceSerial.length() < 2)
continue;
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
continue; // Not a RADGalaxy
auto device = foundDev.device;
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
found.emplace_back(new RADGalaxy(std::move(device)));
break;
}
}
return found;
}
static const std::vector<Network>& GetSupportedNetworks() { static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = { static std::vector<Network> supportedNetworks = {
@ -85,15 +51,13 @@ public:
return supportedNetworks; return supportedNetworks;
} }
RADGalaxy(neodevice_t neodevice) : Device(neodevice) {
initialize<PCAP, RADGalaxySettings>();
getWritableNeoDevice().type = DEVICE_TYPE;
productId = PRODUCT_ID;
}
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
protected: protected:
RADGalaxy(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADGalaxySettings>(makeDriver);
}
void setupPacketizer(Packetizer& packetizer) override { void setupPacketizer(Packetizer& packetizer) override {
Device::setupPacketizer(packetizer); Device::setupPacketizer(packetizer);
packetizer.disableChecksum = true; packetizer.disableChecksum = true;
@ -118,8 +82,8 @@ protected:
// The supported TX networks are the same as the supported RX networks for this device // The supported TX networks are the same as the supported RX networks for this device
void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); } void setupSupportedTXNetworks(std::vector<Network>& txNetworks) override { setupSupportedRXNetworks(txNetworks); }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(radgalaxy_status_t)) if(message->data.size() < sizeof(radgalaxy_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const radgalaxy_status_t* status = reinterpret_cast<const radgalaxy_status_t*>(message->data.data()); const radgalaxy_status_t* status = reinterpret_cast<const radgalaxy_status_t*>(message->data.data());

View File

@ -86,6 +86,12 @@ typedef struct {
RAD_REPORTING_SETTINGS reporting; RAD_REPORTING_SETTINGS reporting;
DISK_SETTINGS disk; DISK_SETTINGS disk;
LOGGER_SETTINGS logger; LOGGER_SETTINGS logger;
ETHERNET_SETTINGS2 ethernet1;// DAQ port on label, NETID_ETHERNET
ETHERNET_SETTINGS2 ethernet2;// LAN port on label, NETID_ETHERNET2
uint16_t network_enables_4;
RAD_GPTP_SETTINGS gPTP;
} radgalaxy_settings_t; } radgalaxy_settings_t;
typedef struct { typedef struct {

View File

@ -1,58 +0,0 @@
#ifndef __RADGIGALOG_ETH_H_
#define __RADGIGALOG_ETH_H_
#ifdef __cplusplus
#include "icsneo/device/tree/radgigalog/radgigalog.h"
#include "icsneo/platform/pcap.h"
namespace icsneo {
class RADGigalogETH : public RADGigalog {
public:
static constexpr const uint16_t PRODUCT_ID = 0x000A;
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
std::vector<std::shared_ptr<Device>> found;
for(auto& foundDev : pcapDevices) {
auto fakedev = std::shared_ptr<RADGigalogETH>(new RADGigalogETH({}));
for (auto& payload : foundDev.discoveryPackets)
fakedev->com->packetizer->input(payload);
for (auto& packet : fakedev->com->packetizer->output()) {
std::shared_ptr<Message> msg;
if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn)
continue; // Not a serial number message
if(sn->deviceSerial.length() < 2)
continue;
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
continue; // Not a RADGigalog
auto device = foundDev.device;
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
found.push_back(std::shared_ptr<RADGigalogETH>(new RADGigalogETH(std::move(device))));
break;
}
}
return found;
}
private:
RADGigalogETH(neodevice_t neodevice) : RADGigalog(neodevice) {
initialize<PCAP, RADGigalogSettings>();
productId = PRODUCT_ID;
}
};
}
#endif // __cplusplus
#endif

View File

@ -1,34 +0,0 @@
#ifndef __RADGIGALOG_USB_H_
#define __RADGIGALOG_USB_H_
#ifdef __cplusplus
#include "icsneo/device/tree/radgigalog/radgigalog.h"
#include "icsneo/platform/ftdi3.h"
namespace icsneo {
class RADGigalogUSB : public RADGigalog {
public:
static constexpr const uint16_t PRODUCT_ID = 0x1203;
static std::vector<std::shared_ptr<Device>> Find() {
std::vector<std::shared_ptr<Device>> found;
for(auto neodevice : FTDI3::FindByProduct(PRODUCT_ID))
found.emplace_back(new RADGigalogUSB(neodevice)); // Creation of the shared_ptr
return found;
}
private:
RADGigalogUSB(neodevice_t neodevice) : RADGigalog(neodevice) {
initialize<FTDI3, RADGigalogSettings>();
productId = PRODUCT_ID;
}
};
}
#endif // __cplusplus
#endif

View File

@ -11,14 +11,18 @@ namespace icsneo {
class RADGigastar : public Device { class RADGigastar : public Device {
public: public:
static constexpr DeviceType::Enum DEVICE_TYPE = DeviceType::RADGigastar; // Serial numbers start with GS
static constexpr const char* SERIAL_START = "GS"; // USB PID is 0x1204, standard driver is FTDI3
// Ethernet MAC allocation is 0x0F, standard driver is Raw
ICSNEO_FINDABLE_DEVICE(RADGigastar, DeviceType::RADGigastar, "GS");
size_t getEthernetActivationLineCount() const override { return 1; } size_t getEthernetActivationLineCount() const override { return 1; }
bool getEthPhyRegControlSupported() const override { return true; }
protected: protected:
RADGigastar(neodevice_t neodevice) : Device(neodevice) { RADGigastar(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
getWritableNeoDevice().type = DEVICE_TYPE; initialize<RADGigastarSettings>(makeDriver);
} }
void setupPacketizer(Packetizer& packetizer) override { void setupPacketizer(Packetizer& packetizer) override {
@ -35,6 +39,7 @@ protected:
void setupEncoder(Encoder& encoder) override { void setupEncoder(Encoder& encoder) override {
Device::setupEncoder(encoder); Device::setupEncoder(encoder);
encoder.supportCANFD = true; encoder.supportCANFD = true;
encoder.supportEthPhy = true;
} }
void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override { void setupSupportedRXNetworks(std::vector<Network>& rxNetworks) override {
@ -81,8 +86,8 @@ protected:
txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end()); txNetworks.insert(txNetworks.end(), supportedTxNetworks.begin(), supportedTxNetworks.end());
} }
void handleDeviceStatus(const std::shared_ptr<Message>& message) override { void handleDeviceStatus(const std::shared_ptr<RawMessage>& message) override {
if(!message || message->data.size() < sizeof(radgigastar_status_t)) if(message->data.size() < sizeof(radgigastar_status_t))
return; return;
std::lock_guard<std::mutex> lk(ioMutex); std::lock_guard<std::mutex> lk(ioMutex);
const radgigastar_status_t* status = reinterpret_cast<const radgigastar_status_t*>(message->data.data()); const radgigastar_status_t* status = reinterpret_cast<const radgigastar_status_t*>(message->data.data());

View File

@ -1,58 +0,0 @@
#ifndef __RADGIGASTAR_ETH_H_
#define __RADGIGASTAR_ETH_H_
#ifdef __cplusplus
#include "icsneo/device/tree/radgigastar/radgigastar.h"
#include "icsneo/platform/pcap.h"
namespace icsneo {
class RADGigastarETH : public RADGigastar {
public:
static constexpr const uint16_t PRODUCT_ID = 0x000F;
static std::vector<std::shared_ptr<Device>> Find(const std::vector<PCAP::PCAPFoundDevice>& pcapDevices) {
std::vector<std::shared_ptr<Device>> found;
for(auto& foundDev : pcapDevices) {
auto fakedev = std::shared_ptr<RADGigastarETH>(new RADGigastarETH({}));
for (auto& payload : foundDev.discoveryPackets)
fakedev->com->packetizer->input(payload);
for (auto& packet : fakedev->com->packetizer->output()) {
std::shared_ptr<Message> msg;
if (!fakedev->com->decoder->decode(msg, packet))
continue; // We failed to decode this packet
if(!msg || msg->network.getNetID() != Network::NetID::Main51)
continue; // Not a message we care about
auto sn = std::dynamic_pointer_cast<SerialNumberMessage>(msg);
if(!sn)
continue; // Not a serial number message
if(sn->deviceSerial.length() < 2)
continue;
if(sn->deviceSerial.substr(0, 2) != SERIAL_START)
continue; // Not a RADGigastar
auto device = foundDev.device;
device.serial[sn->deviceSerial.copy(device.serial, sizeof(device.serial))] = '\0';
found.push_back(std::shared_ptr<RADGigastarETH>(new RADGigastarETH(std::move(device))));
break;
}
}
return found;
}
private:
RADGigastarETH(neodevice_t neodevice) : RADGigastar(neodevice) {
initialize<PCAP, RADGigastarSettings>();
productId = PRODUCT_ID;
}
};
}
#endif // __cplusplus
#endif

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