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,30 +95,61 @@ endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(PLATFORM_SRC set(PLATFORM_SRC
platform/windows/pcap.cpp
platform/windows/registry.cpp platform/windows/registry.cpp
platform/windows/vcp.cpp
platform/windows/internal/pcapdll.cpp
) )
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC
platform/windows/pcap.cpp
platform/windows/internal/pcapdll.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM OR LIBICSNEO_ENABLE_FTDI)
list(APPEND PLATFORM_SRC
platform/windows/vcp.cpp
)
endif()
else() # Darwin or Linux else() # Darwin or Linux
set(PLATFORM_SRC set(PLATFORM_SRC)
platform/posix/ftdi.cpp
platform/posix/pcap.cpp if(LIBICSNEO_ENABLE_FIRMIO)
platform/posix/cdcacm.cpp
)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
list(APPEND PLATFORM_SRC list(APPEND PLATFORM_SRC
platform/posix/darwin/cdcacmdarwin.cpp platform/posix/firmio.cpp
) )
else() # Linux or other endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
list(APPEND PLATFORM_SRC list(APPEND PLATFORM_SRC
platform/posix/linux/cdcacmlinux.cpp platform/posix/pcap.cpp
) )
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") endif()
message(WARNING
"There is no platform port defined for ${CMAKE_SYSTEM_NAME}!\n" if(LIBICSNEO_ENABLE_FTDI)
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly." list(APPEND PLATFORM_SRC
platform/posix/ftdi.cpp
)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
list(APPEND PLATFORM_SRC
platform/posix/cdcacm.cpp
)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
list(APPEND PLATFORM_SRC
platform/posix/darwin/cdcacmdarwin.cpp
) )
else() # Linux or other
list(APPEND PLATFORM_SRC
platform/posix/linux/cdcacmlinux.cpp
)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
message(WARNING
"There is no CDCACM platform port defined for ${CMAKE_SYSTEM_NAME}!\n"
"The Linux platform code will be used, as it will generally allow building, but some devices may not enumerate properly."
)
endif()
endif() endif()
endif() endif()
endif() endif()
@ -127,11 +169,14 @@ endforeach()
set(SRC_FILES set(SRC_FILES
communication/message/flexray/control/flexraycontrolmessage.cpp communication/message/flexray/control/flexraycontrolmessage.cpp
communication/message/neomessage.cpp communication/message/neomessage.cpp
communication/message/ethphymessage.cpp
communication/packet/flexraypacket.cpp communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp communication/packet/canpacket.cpp
communication/packet/ethernetpacket.cpp communication/packet/ethernetpacket.cpp
communication/packet/versionpacket.cpp communication/packet/versionpacket.cpp
communication/packet/iso9141packet.cpp communication/packet/iso9141packet.cpp
communication/packet/ethphyregpacket.cpp
communication/packet/logicaldiskinfopacket.cpp
communication/decoder.cpp communication/decoder.cpp
communication/encoder.cpp communication/encoder.cpp
communication/ethernetpacketizer.cpp communication/ethernetpacketizer.cpp
@ -144,6 +189,14 @@ set(SRC_FILES
device/idevicesettings.cpp device/idevicesettings.cpp
device/devicefinder.cpp device/devicefinder.cpp
device/device.cpp device/device.cpp
device/neodevice.cpp
disk/diskreaddriver.cpp
disk/diskwritedriver.cpp
disk/nulldiskdriver.cpp
disk/neomemorydiskdriver.cpp
disk/plasiondiskreaddriver.cpp
disk/extextractordiskreaddriver.cpp
disk/fat.cpp
${PLATFORM_SRC} ${PLATFORM_SRC}
) )
@ -208,6 +261,22 @@ set_property(TARGET icsneocpp PROPERTY POSITION_INDEPENDENT_CODE ON)
target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums) target_compile_features(icsneocpp PUBLIC cxx_auto_type cxx_constexpr cxx_lambdas cxx_nullptr cxx_range_for cxx_rvalue_references cxx_sizeof_member cxx_strong_enums)
message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS}) message("Loaded extensions: " ${LIBICSNEO_EXTENSION_TARGETS})
target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS}) target_link_libraries(icsneocpp PUBLIC ${LIBICSNEO_EXTENSION_TARGETS})
if(LIBICSNEO_ENABLE_FIRMIO)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FIRMIO)
endif()
if(LIBICSNEO_ENABLE_RAW_ETHERNET)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_RAW_ETHERNET)
endif()
if(LIBICSNEO_ENABLE_CDCACM)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_CDCACM)
endif()
if(LIBICSNEO_ENABLE_FTDI)
target_compile_definitions(icsneocpp PRIVATE ICSNEO_ENABLE_FTDI)
endif()
# fatfs
add_subdirectory(third-party/fatfs)
target_link_libraries(icsneocpp PRIVATE fatfs)
# libftdi # libftdi
if(NOT WIN32) if(NOT WIN32)
@ -220,7 +289,7 @@ if(NOT WIN32)
set(FTDIPP OFF CACHE INTERNAL "") set(FTDIPP OFF CACHE INTERNAL "")
set(FTDI_EEPROM OFF CACHE INTERNAL "") set(FTDI_EEPROM OFF CACHE INTERNAL "")
add_subdirectory(third-party/libftdi) add_subdirectory(third-party/libftdi)
include_directories(${LIBUSB_INCLUDE_DIR}) target_include_directories(icsneocpp PRIVATE ${LIBUSB_INCLUDE_DIR})
endif(NOT WIN32) endif(NOT WIN32)
# winpcap # winpcap
@ -289,6 +358,7 @@ if(NOT WIN32)
target_link_libraries(icsneocpp PUBLIC ftdi1-static) target_link_libraries(icsneocpp PUBLIC ftdi1-static)
target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(icsneocpp PUBLIC ${CMAKE_THREAD_LIBS_INIT})
find_package(PCAP REQUIRED) find_package(PCAP REQUIRED)
target_include_directories(icsneocpp PUBLIC ${PCAP_INCLUDE_DIR})
target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY}) target_link_libraries(icsneocpp PUBLIC ${PCAP_LIBRARY})
endif() endif()
@ -298,22 +368,30 @@ if(LIBICSNEO_BUILD_TESTS)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif() endif()
add_subdirectory(third-party/googletest-master) if (NOT TARGET gtest)
add_subdirectory(third-party/googletest-master)
endif()
if (CMAKE_VERSION VERSION_LESS 2.8.11) if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include") include_directories("${gtest_SOURCE_DIR}/include")
endif() endif()
add_executable(runTests test/main.cpp test/eventmanagertest.cpp) add_executable(libicsneo-tests
test/main.cpp
test/diskdriverreadtest.cpp
test/diskdriverwritetest.cpp
test/eventmanagertest.cpp
test/ethernetpacketizertest.cpp
)
target_link_libraries(runTests gtest gtest_main) target_link_libraries(libicsneo-tests gtest gtest_main)
target_link_libraries(runTests icsneocpp) target_link_libraries(libicsneo-tests icsneocpp)
target_include_directories(runTests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) target_include_directories(libicsneo-tests PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
enable_testing() enable_testing()
add_test(NAME testSuite COMMAND runTests) add_test(NAME libicsneo-test-suite COMMAND libicsneo-tests)
endif() endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})

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))

File diff suppressed because it is too large Load Diff

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

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,87 +1,116 @@
#include "icsneo/communication/message/neomessage.h" #include "icsneo/communication/message/neomessage.h"
#include "icsneo/communication/message/canmessage.h" #include "icsneo/communication/message/canmessage.h"
#include "icsneo/communication/message/ethernetmessage.h" #include "icsneo/communication/message/ethernetmessage.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
using namespace icsneo; using namespace icsneo;
neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) { neomessage_t icsneo::CreateNeoMessage(const std::shared_ptr<Message> message) {
// This function is not responsible for storing the message! // This function is not responsible for storing the message!
// Keep the shared_ptr around for the lifetime of the data access // Keep the shared_ptr around for the lifetime of the data access
const auto type = message->network.getType();
neomessage_t neomsg = {}; // Clear out the memory neomessage_t neomsg = {}; // Clear out the memory
neomsg.netid = (uint32_t)message->network.getNetID(); neomsg.messageType = (neomessagetype_t)message->type;
neomsg.type = (uint8_t)type;
neomsg.description = message->description;
neomsg.length = message->data.size();
neomsg.data = message->data.data();
neomsg.timestamp = message->timestamp; neomsg.timestamp = message->timestamp;
neomsg.status.globalError = message->error; switch (message->type)
neomsg.status.transmitMessage = message->transmitted; {
case Message::Type::Frame: {
neomessage_frame_t& frame = *(neomessage_frame_t*)&neomsg;
auto framemsg = std::static_pointer_cast<Frame>(message);
const auto netType = framemsg->network.getType();
frame.netid = (neonetid_t)framemsg->network.getNetID();
frame.type = (neonettype_t)netType;
frame.description = framemsg->description;
frame.length = framemsg->data.size();
frame.data = framemsg->data.data();
frame.timestamp = framemsg->timestamp;
frame.status.globalError = framemsg->error;
frame.status.transmitMessage = framemsg->transmitted;
switch(type) { switch(netType) {
case Network::Type::CAN: case Network::Type::CAN:
case Network::Type::SWCAN: case Network::Type::SWCAN:
case Network::Type::LSFTCAN: { case Network::Type::LSFTCAN: {
neomessage_can_t& can = *(neomessage_can_t*)&neomsg; neomessage_can_t& can = *(neomessage_can_t*)&neomsg;
auto canmsg = std::static_pointer_cast<CANMessage>(message); auto canmsg = std::static_pointer_cast<CANMessage>(message);
can.arbid = canmsg->arbid; can.arbid = canmsg->arbid;
can.dlcOnWire = canmsg->dlcOnWire; can.dlcOnWire = canmsg->dlcOnWire;
can.status.extendedFrame = canmsg->isExtended; can.status.extendedFrame = canmsg->isExtended;
can.status.remoteFrame = canmsg->isRemote; can.status.remoteFrame = canmsg->isRemote;
can.status.canfdRTR = canmsg->isRemote; can.status.canfdRTR = canmsg->isRemote;
can.status.canfdFDF = canmsg->isCANFD; can.status.canfdFDF = canmsg->isCANFD;
can.status.canfdBRS = canmsg->baudrateSwitch; can.status.canfdBRS = canmsg->baudrateSwitch;
can.status.canfdESI = canmsg->errorStateIndicator; can.status.canfdESI = canmsg->errorStateIndicator;
break; break;
}
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg;
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message);
eth.preemptionFlags = ethmsg->preemptionFlags;
eth.status.incompleteFrame = ethmsg->frameTooShort;
// TODO Fill in extra status bits
//eth.status.xyz = ethmsg->preemptionEnabled;
//eth.status.xyz = ethmsg->fcsAvailable;
//eth.status.xyz = ethmsg->noPadding;
break;
}
default:
// TODO Implement others
break;
} }
case Network::Type::Ethernet: { break;
neomessage_eth_t& eth = *(neomessage_eth_t*)&neomsg; }
auto ethmsg = std::static_pointer_cast<EthernetMessage>(message); case Message::Type::CANErrorCount: {
eth.preemptionFlags = ethmsg->preemptionFlags; neomessage_can_error_t& canerror = *(neomessage_can_error_t*)&neomsg;
eth.status.incompleteFrame = ethmsg->frameTooShort; auto canerrormsg = std::static_pointer_cast<CANErrorCountMessage>(message);
// TODO Fill in extra status bits canerror.transmitErrorCount = canerrormsg->transmitErrorCount;
//eth.status.xyz = ethmsg->preemptionEnabled; canerror.receiveErrorCount = canerrormsg->receiveErrorCount;
//eth.status.xyz = ethmsg->fcsAvailable; canerror.status.canBusOff = canerrormsg->busOff;
//eth.status.xyz = ethmsg->noPadding; canerror.netid = (neonetid_t)canerrormsg->network.getNetID();
break; canerror.type = (neonettype_t)canerrormsg->network.getType();
} break;
default: }
// TODO Implement others default:
break; break;
} }
return neomsg; return neomsg;
} }
std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) { std::shared_ptr<Message> icsneo::CreateMessageFromNeoMessage(const neomessage_t* neomessage) {
const Network network = neomessage->netid; switch((Message::Type)neomessage->messageType) {
switch(network.getType()) { case Message::Type::Frame: {
case Network::Type::CAN: const Network network = ((neomessage_frame_t*)neomessage)->netid;
case Network::Type::SWCAN: switch(network.getType()) {
case Network::Type::LSFTCAN: { case Network::Type::CAN:
neomessage_can_t& can = *(neomessage_can_t*)neomessage; case Network::Type::SWCAN:
auto canmsg = std::make_shared<CANMessage>(); case Network::Type::LSFTCAN: {
canmsg->network = network; neomessage_can_t& can = *(neomessage_can_t*)neomessage;
canmsg->description = can.description; auto canmsg = std::make_shared<CANMessage>();
canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length); canmsg->network = network;
canmsg->arbid = can.arbid; canmsg->description = can.description;
canmsg->isExtended = can.status.extendedFrame; canmsg->data.insert(canmsg->data.end(), can.data, can.data + can.length);
canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR; canmsg->arbid = can.arbid;
canmsg->isCANFD = can.status.canfdFDF; canmsg->dlcOnWire = can.dlcOnWire;
canmsg->baudrateSwitch = can.status.canfdBRS; canmsg->isExtended = can.status.extendedFrame;
canmsg->errorStateIndicator = can.status.canfdESI; canmsg->isRemote = can.status.remoteFrame | can.status.canfdRTR;
return canmsg; canmsg->isCANFD = can.status.canfdFDF;
canmsg->baudrateSwitch = can.status.canfdBRS;
canmsg->errorStateIndicator = can.status.canfdESI;
return canmsg;
}
case Network::Type::Ethernet: {
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
auto ethmsg = std::make_shared<EthernetMessage>();
ethmsg->network = network;
ethmsg->description = eth.description;
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
return ethmsg;
}
default: break;
}
break;
} }
case Network::Type::Ethernet: { default: break;
neomessage_eth_t& eth = *(neomessage_eth_t*)neomessage;
auto ethmsg = std::make_shared<EthernetMessage>();
ethmsg->network = network;
ethmsg->description = eth.description;
ethmsg->data.insert(ethmsg->data.end(), eth.data, eth.data + eth.length);
return ethmsg;
}
default:
// TODO Implement others
return std::shared_ptr<Message>();
} }
return std::shared_ptr<Message>();
} }

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,86 +1,129 @@
#include "icsneo/communication/packet/canpacket.h" #include "icsneo/communication/packet/canpacket.h"
#include "icsneo/communication/message/canerrorcountmessage.h"
#include "icsneo/platform/optional.h" #include "icsneo/platform/optional.h"
using namespace icsneo; using namespace icsneo;
static optional<uint8_t> CANFD_DLCToLength(uint8_t length) { static optional<uint8_t> CAN_DLCToLength(uint8_t length, bool fd) {
if (length < 8) if (length <= 8)
return length; return length;
switch(length) { if (fd) {
case 0x9: switch(length) {
return 12; case 0x9:
case 0xa: return uint8_t(12);
return 16; case 0xa:
case 0xb: return uint8_t(16);
return 20; case 0xb:
case 0xc: return uint8_t(20);
return 24; case 0xc:
case 0xd: return uint8_t(24);
return 32; case 0xd:
case 0xe: return uint8_t(32);
return 48; case 0xe:
case 0xf: return uint8_t(48);
return 64; case 0xf:
} return uint8_t(64);
return nullopt;
}
std::shared_ptr<CANMessage> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
auto msg = std::make_shared<CANMessage>();
// Arb ID
if(data->header.IDE) { // Extended 29-bit ID
msg->arbid = (data->header.SID & 0x7ff) << 18;
msg->arbid |= (data->eid.EID & 0xfff) << 6;
msg->arbid |= (data->dlc.EID2 & 0x3f);
msg->isExtended = true;
} else { // Standard 11-bit ID
msg->arbid = data->header.SID;
}
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// DLC
uint8_t length = data->dlc.DLC;
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI;
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(length);
if (lenFromDLC)
length = *lenFromDLC;
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
// We don't want to overread our buffer, though, so make sure we cap the length
length = 8;
}
// Data
// The first 8 bytes are always in the standard place
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
msg->data.resize(length); // This data will be all zeros, but the length will be set
msg->isRemote = true;
} else {
msg->data.reserve(length);
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
} }
} }
msg->transmitted = data->eid.TXMSG; return nullopt;
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb; }
msg->description = data->stats;
return msg; static optional<uint8_t> CAN_LengthToDLC(size_t dataLength, bool fd)
{
if (dataLength <= 8)
return uint8_t(dataLength);
if (fd) {
if (dataLength <= 12)
return uint8_t(0x9);
else if (dataLength <= 16)
return uint8_t(0xA);
else if (dataLength <= 20)
return uint8_t(0xB);
else if (dataLength <= 24)
return uint8_t(0xC);
else if (dataLength <= 32)
return uint8_t(0xD);
else if (dataLength <= 48)
return uint8_t(0xE);
else if (dataLength <= 64)
return uint8_t(0xF);
}
return nullopt;
}
std::shared_ptr<Message> HardwareCANPacket::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
const HardwareCANPacket* data = (const HardwareCANPacket*)bytestream.data();
if(data->dlc.RB1) { // Change counts reporting
const bool busOff = data->data[0] & 0b00100000;
auto msg = std::make_shared<CANErrorCountMessage>(data->data[2], data->data[1], busOff);
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
return msg;
} else { // CAN Frame
auto msg = std::make_shared<CANMessage>();
// Arb ID
if(data->header.IDE) { // Extended 29-bit ID
msg->arbid = (data->header.SID & 0x7ff) << 18;
msg->arbid |= (data->eid.EID & 0xfff) << 6;
msg->arbid |= (data->dlc.EID2 & 0x3f);
msg->isExtended = true;
} else { // Standard 11-bit ID
msg->arbid = data->header.SID;
}
// This timestamp is raw off the device (in timestampResolution increments)
// Decoder will fix as it has information about the timestampResolution increments
msg->timestamp = data->timestamp.TS;
// DLC
uint8_t length = data->dlc.DLC;
msg->dlcOnWire = length; // This will hold the real DLC on wire 0x0 - 0xF
if(data->header.EDL && data->timestamp.IsExtended) { // CAN FD
msg->isCANFD = true;
msg->baudrateSwitch = data->header.BRS; // CAN FD Baudrate Switch
msg->errorStateIndicator = data->header.ESI;
const optional<uint8_t> lenFromDLC = CAN_DLCToLength(length, true);
if (lenFromDLC)
length = *lenFromDLC;
} else if(length > 8) { // This is a standard CAN frame with a length of more than 8
// Yes, this is possible. On the wire, the length field is a nibble, and we do want to return an accurate value
// We don't want to overread our buffer, though, so make sure we cap the length
length = 8;
}
// Data
// The first 8 bytes are always in the standard place
if((data->dlc.RTR && data->header.IDE) || (!data->header.IDE && data->header.SRR)) { // Remote Request Frame
msg->data.resize(length); // This data will be all zeros, but the length will be set
msg->isRemote = true;
} else {
msg->data.reserve(length);
msg->data.insert(msg->data.end(), data->data, data->data + (length > 8 ? 8 : length));
if(length > 8) { // If there are more than 8 bytes, they come at the end of the message
// Messages with extra data are formatted as message, then uint16_t netid, then uint16_t length, then extra data
const auto extraDataStart = bytestream.begin() + sizeof(HardwareCANPacket) + 2 + 2;
msg->data.insert(msg->data.end(), extraDataStart, extraDataStart + (length - 8));
}
}
msg->transmitted = data->eid.TXMSG;
msg->error = data->eid.TXAborted || data->eid.TXError || data->eid.TXLostArb;
msg->description = data->stats;
return msg;
}
} }
bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) { bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector<uint8_t>& result, const device_eventhandler_t& report) {
@ -90,115 +133,38 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
} }
const size_t dataSize = message.data.size(); const size_t dataSize = message.data.size();
if(dataSize > 64 || (dataSize > 8 && !message.isCANFD)) { optional<uint8_t> dlc = CAN_LengthToDLC(dataSize, message.isCANFD);
if (!dlc.has_value()) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error); report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // Too much data for the protocol return false; // Too much data for the protocol
} }
if(message.dlcOnWire > 0xf) { if (message.dlcOnWire != 0) {
// The DLC is only a nibble if(message.dlcOnWire > 0xf) {
// It is actually possible to transmit a standard CAN frame with a DLC > 8 // The DLC is only a nibble
// While it is invalid, most controllers will still pass along the received // It is actually possible to transmit a standard CAN frame with a DLC > 8
// frame and 8 bytes of data, so it may be desirable to test behavior with // While it is invalid, most controllers will still pass along the received
// these frames. We let you do it if you set `message.dlcOnWire` for transmit. // frame and 8 bytes of data, so it may be desirable to test behavior with
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error); // these frames. We let you do it if you set `message.dlcOnWire` for transmit.
return false;
}
uint8_t lengthNibble = uint8_t(message.data.size());
const optional<uint8_t> lenFromDLC = CANFD_DLCToLength(message.dlcOnWire);
if (lenFromDLC.has_value() && *lenFromDLC != 0) {
if (*lenFromDLC < lengthNibble) {
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error); report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; return false;
} }
if (*lenFromDLC > lengthNibble) if (message.dlcOnWire < *dlc) {
lengthNibble = *lenFromDLC; report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false;
}
if (message.dlcOnWire > *dlc)
dlc = message.dlcOnWire;
} }
uint8_t paddingBytes = 0; // The only way this fails is if we're transmitting a DLC > 8 on standard CAN
if(lengthNibble > 8) { const uint8_t paddedLength = CAN_DLCToLength(*dlc, message.isCANFD).value_or(8);
switch(lengthNibble) { const uint8_t paddingBytes = uint8_t(paddedLength - dataSize);
case 9: paddingBytes++;
case 10: paddingBytes++;
case 11: paddingBytes++;
case 12:
lengthNibble = 0x9;
break;
case 13: paddingBytes++;
case 14: paddingBytes++;
case 15: paddingBytes++;
case 16:
lengthNibble = 0xA;
break;
case 17: paddingBytes++;
case 18: paddingBytes++;
case 19: paddingBytes++;
case 20:
lengthNibble = 0xB;
break;
case 21: paddingBytes++;
case 22: paddingBytes++;
case 23: paddingBytes++;
case 24:
lengthNibble = 0xC;
break;
case 25: paddingBytes++;
case 26: paddingBytes++;
case 27: paddingBytes++;
case 28: paddingBytes++;
case 29: paddingBytes++;
case 30: paddingBytes++;
case 31: paddingBytes++;
case 32:
lengthNibble = 0xD;
break;
case 33: paddingBytes++;
case 34: paddingBytes++;
case 35: paddingBytes++;
case 36: paddingBytes++;
case 37: paddingBytes++;
case 38: paddingBytes++;
case 39: paddingBytes++;
case 40: paddingBytes++;
case 41: paddingBytes++;
case 42: paddingBytes++;
case 43: paddingBytes++;
case 44: paddingBytes++;
case 45: paddingBytes++;
case 46: paddingBytes++;
case 47: paddingBytes++;
case 48:
lengthNibble = 0xE;
break;
case 49: paddingBytes++;
case 50: paddingBytes++;
case 51: paddingBytes++;
case 52: paddingBytes++;
case 53: paddingBytes++;
case 54: paddingBytes++;
case 55: paddingBytes++;
case 56: paddingBytes++;
case 57: paddingBytes++;
case 58: paddingBytes++;
case 59: paddingBytes++;
case 60: paddingBytes++;
case 61: paddingBytes++;
case 62: paddingBytes++;
case 63: paddingBytes++;
case 64:
lengthNibble = 0xF;
break;
default:
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; // CAN FD frame may have had an incorrect byte count
}
}
// Pre-allocate as much memory as we will possibly need for speed // Pre-allocate as much memory as we will possibly need for speed
result.reserve(17 + dataSize + paddingBytes); result.reserve(16 + dataSize + paddingBytes);
result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF)); result.push_back(0 /* byte count here later */ << 4 | (uint8_t(message.network.getNetID()) & 0xF));
@ -233,7 +199,7 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
// Status and DLC bits // Status and DLC bits
if(message.isCANFD) { if(message.isCANFD) {
result.push_back(0x0F); // FD Frame result.push_back(0x0F); // FD Frame
uint8_t fdStatusByte = lengthNibble; uint8_t fdStatusByte = *dlc;
if(message.baudrateSwitch) if(message.baudrateSwitch)
fdStatusByte |= 0x80; // BRS status bit fdStatusByte |= 0x80; // BRS status bit
// The firmware does not yet support transmitting ESI // The firmware does not yet support transmitting ESI
@ -241,13 +207,12 @@ bool HardwareCANPacket::EncodeFromMessage(const CANMessage& message, std::vector
} else { } else {
// TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable // TODO Support high voltage wakeup, bitwise-or in 0x8 here to enable
uint8_t statusNibble = message.isRemote ? 0x4 : 0x0; uint8_t statusNibble = message.isRemote ? 0x4 : 0x0;
result.push_back((statusNibble << 4) | lengthNibble); result.push_back((statusNibble << 4) | *dlc);
} }
// Now finally the payload // Now finally the payload
result.insert(result.end(), message.data.begin(), message.data.end()); result.insert(result.end(), message.data.begin(), message.data.end());
result.resize(result.size() + paddingBytes); result.resize(result.size() + paddingBytes);
result.push_back(0);
// Fill in the length byte from earlier // Fill in the length byte from earlier
result[0] |= result.size() << 4; result[0] |= result.size() << 4;

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,22 +807,32 @@ void Device::forEachExtension(std::function<bool(const std::shared_ptr<DeviceExt
} }
void Device::handleInternalMessage(std::shared_ptr<Message> message) { void Device::handleInternalMessage(std::shared_ptr<Message> message) {
switch(message->network.getNetID()) { switch(message->type) {
case Network::NetID::Reset_Status: case Message::Type::ResetStatus:
latestResetStatus = std::dynamic_pointer_cast<ResetStatusMessage>(message); latestResetStatus = std::static_pointer_cast<ResetStatusMessage>(message);
break; break;
case Network::NetID::Device: { case Message::Type::RawMessage: {
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message); auto rawMessage = std::static_pointer_cast<RawMessage>(message);
if(canmsg) switch(rawMessage->network.getNetID()) {
handleNeoVIMessage(std::move(canmsg)); case Network::NetID::Device: {
// Device is not guaranteed to be a CANMessage, it might be a RawMessage
// if it couldn't be decoded to a CANMessage. We only care about the
// CANMessage decoding right now.
auto canmsg = std::dynamic_pointer_cast<CANMessage>(message);
if(canmsg)
handleNeoVIMessage(std::move(canmsg));
break;
}
case Network::NetID::DeviceStatus:
// Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(rawMessage);
break;
default:
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
}
break; break;
} }
case Network::NetID::DeviceStatus: default: break;
// Device Status format is unique per device, so the devices need to decode it themselves
handleDeviceStatus(message);
break;
default:
break; //std::cout << "HandleInternalMessage got a message from " << message->network << " and it was unhandled!" << std::endl;
} }
forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) { forEachExtension([&](const std::shared_ptr<DeviceExtension>& ext) {
ext->handleMessage(message); ext->handleMessage(message);
@ -766,3 +891,34 @@ void Device::updateLEDState() {
std::vector<uint8_t> args {(uint8_t) ledState}; std::vector<uint8_t> args {(uint8_t) ledState};
com->sendCommand(Command::UpdateLEDState, args); com->sendCommand(Command::UpdateLEDState, args);
} }
optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message, std::chrono::milliseconds timeout) {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullopt;
}
if(!getEthPhyRegControlSupported()) {
report(APIEvent::Type::EthPhyRegisterControlNotAvailable, APIEvent::Severity::Error);
return nullopt;
}
if(!isOnline()) {
report(APIEvent::Type::DeviceCurrentlyOffline, APIEvent::Severity::Error);
return nullopt;
}
std::vector<uint8_t> bytes;
HardwareEthernetPhyRegisterPacket::EncodeFromMessage(message, bytes, report);
std::shared_ptr<Message> response = com->waitForMessageSync(
[this, bytes](){ return com->sendCommand(Command::PHYControlRegisters, bytes); },
std::make_shared<MessageFilter>(Network::NetID::EthPHYControl), timeout);
if(!response) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return nullopt;
}
auto retMsg = std::static_pointer_cast<EthPhyMessage>(response);
if(!retMsg) {
return nullopt;
}
return make_optional<EthPhyMessage>(*retMsg);
}

View File

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

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[msg->controller]->_setStatus(msg);
controllers[status->controller]->_setStatus(status);
}
break; break;
} }
break; break;
@ -47,18 +45,18 @@ void FlexRay::Extension::handleMessage(const std::shared_ptr<Message>& message)
} }
} }
bool FlexRay::Extension::transmitHook(const std::shared_ptr<Message>& message, bool& success) { bool FlexRay::Extension::transmitHook(const std::shared_ptr<Frame>& frame, bool& success) {
if(!message || message->network.getType() != Network::Type::FlexRay) if(!frame || frame->network.getType() != Network::Type::FlexRay)
return true; // Don't hook non-FlexRay messages return true; // Don't hook non-FlexRay messages
success = false; success = false;
std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(message); std::shared_ptr<FlexRayMessage> frmsg = std::dynamic_pointer_cast<FlexRayMessage>(frame);
if(!frmsg) if(!frmsg)
return false; return false;
for(auto& controller : controllers) { for(auto& controller : controllers) {
if(controller->getNetwork() != message->network) if(controller->getNetwork() != frame->network)
continue; continue;
success |= controller->transmit(frmsg); success |= controller->transmit(frmsg);
} }

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,24 +471,34 @@ int main() {
// Print out the received messages // Print out the received messages
for(size_t i = 0; i < msgCount; i++) { for(size_t i = 0; i < msgCount; i++) {
neomessage_t* msg = &msgs[i]; const neomessage_t* msg = &msgs[i];
switch(msg->type) { switch(msg->messageType) {
case ICSNEO_NETWORK_TYPE_CAN: // CAN case ICSNEO_MESSAGE_TYPE_FRAME: {
{ const neomessage_frame_t* frame = (neomessage_frame_t*)msg;
neomessage_can_t* canMsg = (neomessage_can_t*) msg; switch(frame->type) {
printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length); case ICSNEO_NETWORK_TYPE_CAN: {
for(size_t i = 0; i < canMsg->length; i++) { neomessage_can_t* canMsg = (neomessage_can_t*)frame;
printf("%02x ", canMsg->data[i]); printf("\t0x%03x [%zu] ", canMsg->arbid, canMsg->length);
for(size_t i = 0; i < canMsg->length; i++) {
printf("%02x ", canMsg->data[i]);
}
if(canMsg->status.transmitMessage)
printf("TX%s %04x ", canMsg->status.globalError ? " ERR" : "", canMsg->description);
printf("(%"PRIu64")\n", canMsg->timestamp);
break;
}
default:
printf("\tMessage on netid %d with length %zu\n", frame->netid, frame->length);
break;
}
break;
}
case ICSNEO_MESSAGE_TYPE_CAN_ERROR_COUNT: {
const neomessage_can_error_t* cec = (neomessage_can_error_t*)msg;
printf("\tCAN error counts changed, TEC=%d, REC=%d%s", cec->transmitErrorCount, cec->receiveErrorCount,
cec->status.canBusOff ? " (Bus Off)" : "");
break;
} }
if(canMsg->status.transmitMessage)
printf("TX%s %04x ", canMsg->status.globalError ? " ERR" : "", canMsg->description);
printf("(%"PRIu64")\n", canMsg->timestamp);
break;
}
default:
if(msg->netid != 0)
printf("\tMessage on netid %d with length %zu\n", msg->netid, msg->length);
break;
} }
} }
printf("\n"); printf("\n");

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,82 +126,118 @@ int main() {
device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k device->setPollingMessageLimit(100000); // Feel free to set a limit if you like, the default is a conservative 20k
// Keep in mind that 20k messages comes quickly at high bus loads! // Keep in mind that 20k messages comes quickly at high bus loads!
// We can transmit messages
std::cout << "\tTransmitting an extended CAN FD frame... ";
auto txMessage5 = std::make_shared<icsneo::CANMessage>();
txMessage5->network = icsneo::Network::NetID::HSCAN;
txMessage5->arbid = 0x1C5001C5;
txMessage5->data.insert(txMessage5->data.end(), {0xaa, 0xbb, 0xcc});
// The DLC will come from the length of the data vector
txMessage5->isExtended = true;
txMessage5->isCANFD = true;
ret = device->transmit(txMessage5); // This will return false if the device does not support CAN FD, or does not have HSCAN
std::cout << (ret ? "OK" : "FAIL") << std::endl;
// We can also register a handler // We can also register a handler
std::cout << "\tStreaming messages in for 3 seconds... " << std::endl; std::cout << "\tStreaming messages in for 3 seconds... " << std::endl;
// MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation // MessageCallbacks are powerful, and can filter on things like ArbID for you. See the documentation
auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) { auto handler = device->addMessageCallback(icsneo::MessageCallback([](std::shared_ptr<icsneo::Message> message) {
switch(message->network.getType()) { switch(message->type) {
case icsneo::Network::Type::CAN: { case icsneo::Message::Type::Frame: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely // A message of type Frame is guaranteed to be a Frame, so we can static cast safely
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message); auto frame = std::static_pointer_cast<icsneo::Frame>(message);
switch(frame->network.getType()) {
case icsneo::Network::Type::CAN: {
// A message of type CAN is guaranteed to be a CANMessage, so we can static cast safely
auto canMessage = std::static_pointer_cast<icsneo::CANMessage>(message);
std::cout << "\t\tCAN "; std::cout << "\t\t" << frame->network << ' ';
if(canMessage->isCANFD) { if(canMessage->isCANFD) {
std::cout << "FD "; std::cout << "FD ";
if(!canMessage->baudrateSwitch) if(!canMessage->baudrateSwitch)
std::cout << "(No BRS) "; std::cout << "(No BRS) ";
}
// Print the Arbitration ID
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3)
<< std::setfill('0') << canMessage->arbid;
// Print the DLC
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
// Print the data
for(auto& databyte : canMessage->data)
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n";
break;
}
case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec
<< ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
// Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) {
if(i % 8 == 0)
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
}
std::cout << std::dec << std::endl;
break;
}
case icsneo::Network::Type::ISO9141: {
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
// and that this example loads the device defaults at the very end.
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
std::cout << "\t\t" << isoMessage->network << ' ';
// Print the header bytes
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
// Print the data length
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
// Print the data
for(auto& databyte : isoMessage->data)
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
break;
}
default:
// Ignoring non-network messages
break;
} }
break;
} // end of icsneo::Message::Type::Frame
case icsneo::Message::Type::CANErrorCount: {
// A message of type CANErrorCount is guaranteed to be a CANErrorCount, so we can static cast safely
auto cec = std::static_pointer_cast<icsneo::CANErrorCountMessage>(message);
// Print the Arbitration ID // Print the error counts
std::cout << "0x" << std::hex << std::setw(canMessage->isExtended ? 8 : 3) << std::setfill('0') << canMessage->arbid; std::cout << "\t\t" << cec->network << " error counts changed, REC=" << std::to_string(cec->receiveErrorCount)
<< " TEC=" << std::to_string(cec->transmitErrorCount) << " (" << (cec->busOff ? "" : "Not ") << "Bus Off) ";
// Print the DLC
std::cout << std::dec << " [" << canMessage->data.size() << "] ";
// Print the data
for(auto& databyte : canMessage->data)
std::cout << std::hex << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp // Print the timestamp
std::cout << std::dec << '(' << canMessage->timestamp << " ns since 1/1/2007)\n"; std::cout << std::dec << '(' << cec->timestamp << " ns since 1/1/2007)\n";
break;
}
case icsneo::Network::Type::Ethernet: {
auto ethMessage = std::static_pointer_cast<icsneo::EthernetMessage>(message);
std::cout << "\t\t" << ethMessage->network << " Frame - " << std::dec << ethMessage->data.size() << " bytes on wire\n";
std::cout << "\t\t Timestamped:\t"<< ethMessage->timestamp << " ns since 1/1/2007\n";
// The MACAddress may be printed directly or accessed with the `data` member
std::cout << "\t\t Source:\t" << ethMessage->getSourceMAC() << "\n";
std::cout << "\t\t Destination:\t" << ethMessage->getDestinationMAC();
// Print the data
for(size_t i = 0; i < ethMessage->data.size(); i++) {
if(i % 8 == 0)
std::cout << "\n\t\t " << std::hex << std::setw(4) << std::setfill('0') << i << '\t';
std::cout << std::hex << std::setw(2) << (uint32_t)ethMessage->data[i] << ' ';
}
std::cout << std::dec << std::endl;
break;
}
case icsneo::Network::Type::ISO9141: {
// Note that the default settings on some devices have ISO9141 disabled by default in favor of LIN
// and that this example loads the device defaults at the very end.
// A message of type ISO9414 is guaranteed to be an ISO9141Message, so we can static cast safely
auto isoMessage = std::static_pointer_cast<icsneo::ISO9141Message>(message);
std::cout << "\t\t" << isoMessage->network << ' ';
// Print the header bytes
std::cout << '(' << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[0] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[1] << ' ';
std::cout << std::setfill('0') << std::setw(2) << (uint32_t)isoMessage->header[2] << ") ";
// Print the data length
std::cout << std::dec << " [" << isoMessage->data.size() << "] ";
// Print the data
for(auto& databyte : isoMessage->data)
std::cout << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)databyte << ' ';
// Print the timestamp
std::cout << std::dec << '(' << isoMessage->timestamp << " ns since 1/1/2007)\n";
break; break;
} }
default: default:
// Ignoring non-network messages // Ignoring other types of messages
break; break;
} }
})); }));

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;
if(!matchNetID(message->network.getNetID()))
return false; return false;
if(message->type == Message::Type::Frame || message->type == Message::Type::Main51 ||
message->type == Message::Type::RawMessage || message->type == Message::Type::ReadSettings) {
RawMessage& frame = *static_cast<RawMessage*>(message.get());
if(!matchNetworkType(frame.network.getType()))
return false;
if(!matchNetID(frame.network.getNetID()))
return false;
}
return true; return true;
} }
private: protected:
Network::Type type = Network::Type::Any; Message::Type messageType = Message::Type::Invalid; // Used here for "any"
bool matchType(Network::Type mtype) const { bool matchMessageType(Message::Type mtype) const {
if(type == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny)) if(messageType == Message::Type::Invalid && ((neomessagetype_t(mtype) & 0x8000) == 0 || includeInternalInAny))
return true; return true;
return type == mtype; return messageType == mtype;
}
Network::Type networkType = Network::Type::Any;
bool matchNetworkType(Network::Type mtype) const {
if(networkType == Network::Type::Any && (mtype != Network::Type::Internal || includeInternalInAny))
return true;
return networkType == mtype;
} }
Network::NetID netid = Network::NetID::Any; Network::NetID netid = Network::NetID::Any;

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