8 Commits
38 changed files with 565 additions and 40 deletions
+5
View File
@@ -1,3 +1,6 @@
default:
interruptible: true
variables: variables:
DEBIAN_FRONTEND: noninteractive DEBIAN_FRONTEND: noninteractive
LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT} LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT}
@@ -335,6 +338,7 @@ build python/windows:
deploy python/pypi: deploy python/pypi:
stage: deploy stage: deploy
interruptible: false
variables: variables:
TWINE_USERNAME: __token__ TWINE_USERNAME: __token__
TWINE_PASSWORD: $PYPI_TOKEN TWINE_PASSWORD: $PYPI_TOKEN
@@ -359,6 +363,7 @@ deploy python/pypi:
push github: push github:
stage: deploy stage: deploy
interruptible: false
tags: tags:
- linux-build - linux-build
image: alpine:latest image: alpine:latest
+2
View File
@@ -570,9 +570,11 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/a2bencoderdecodertest.cpp test/unit/a2bencoderdecodertest.cpp
test/unit/mdioencoderdecodertest.cpp test/unit/mdioencoderdecodertest.cpp
test/unit/livedataencoderdecodertest.cpp test/unit/livedataencoderdecodertest.cpp
test/unit/macsectest.cpp
test/unit/ringbuffertest.cpp test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp test/unit/apperrordecodertest.cpp
test/unit/icsneoc2.cpp test/unit/icsneoc2.cpp
test/unit/ethphyregistertest.cpp
test/unit/windowsstrings.cpp test/unit/windowsstrings.cpp
test/unit/periodictest.cpp test/unit/periodictest.cpp
) )
+1
View File
@@ -471,6 +471,7 @@ icsneoc2_error_t icsneoc2_message_lin_status_flags_get(const icsneoc2_message_t*
if(lin_msg->statusFlags.HasUpdatedResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE; if(lin_msg->statusFlags.HasUpdatedResponderOnce) *status_flags |= ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE;
if(lin_msg->statusFlags.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED; if(lin_msg->statusFlags.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED;
if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY; if(lin_msg->statusFlags.BreakOnly) *status_flags |= ICSNEOC2_LIN_STATUS_BREAK_ONLY;
if(lin_msg->statusFlags.WakeupRequest) *status_flags |= ICSNEOC2_LIN_STATUS_WAKEUP_REQUEST;
return icsneoc2_error_success; return icsneoc2_error_success;
} }
+1 -2
View File
@@ -65,7 +65,6 @@ void EventManager::add(APIEvent event) {
std::lock_guard<std::mutex> eventsLock(eventsMutex); std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event); addEventInternal(event);
} // free the lock so that callbacks may modify events } // free the lock so that callbacks may modify events
runCallbacks(event);
} else { } else {
std::lock_guard<std::mutex> errorsLock(errorsMutex); std::lock_guard<std::mutex> errorsLock(errorsMutex);
lastUserErrors[std::this_thread::get_id()] = event; lastUserErrors[std::this_thread::get_id()] = event;
@@ -75,8 +74,8 @@ void EventManager::add(APIEvent event) {
std::lock_guard<std::mutex> eventsLock(eventsMutex); std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event); addEventInternal(event);
} // free the lock so that callbacks may modify events } // free the lock so that callbacks may modify events
runCallbacks(event);
} }
runCallbacks(event);
} }
void EventManager::addEventInternal(APIEvent event) { void EventManager::addEventInternal(APIEvent event) {
+11 -1
View File
@@ -40,6 +40,9 @@ pybind11_add_module(icsneopy
icsneopy/communication/message/livedatamessage.cpp icsneopy/communication/message/livedatamessage.cpp
icsneopy/communication/message/callback/messagecallback.cpp icsneopy/communication/message/callback/messagecallback.cpp
icsneopy/communication/message/filter/messagefilter.cpp icsneopy/communication/message/filter/messagefilter.cpp
icsneopy/communication/message/filter/main51messagefilter.cpp
icsneopy/communication/message/main51message.cpp
icsneopy/communication/command.cpp
icsneopy/core/macseccfg.cpp icsneopy/core/macseccfg.cpp
icsneopy/flexray/flexray.cpp icsneopy/flexray/flexray.cpp
icsneopy/disk/diskdriver.cpp icsneopy/disk/diskdriver.cpp
@@ -57,7 +60,14 @@ install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN_EXE stubgen) find_program(STUBGEN_EXE stubgen)
if(STUBGEN_EXE) if(STUBGEN_EXE)
add_custom_command(TARGET icsneopy POST_BUILD COMMAND stubgen -v -p icsneopy -o .) # Multi-config generators put the extension in Release/ or Debug/. Import
# that freshly built module, not a globally installed older icsneopy.
add_custom_command(TARGET icsneopy POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E rm -f "${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi"
COMMAND "${STUBGEN_EXE}" -v -p icsneopy -o "${CMAKE_CURRENT_BINARY_DIR}"
WORKING_DIRECTORY "$<TARGET_FILE_DIR:icsneopy>"
VERBATIM
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi py.typed DESTINATION icsneopy) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/icsneopy.pyi py.typed DESTINATION icsneopy)
endif() endif()
@@ -0,0 +1,40 @@
#include <pybind11/pybind11.h>
#include <pybind11/native_enum.h>
#include "icsneo/communication/command.h"
namespace icsneo {
void init_command(pybind11::module_& m) {
pybind11::native_enum<Command>(m, "Command", "enum.IntEnum")
.value("Main51RxBufferOverflow", Command::Main51RxBufferOverflow)
.value("Main51StartCmd", Command::Main51StartCmd)
.value("Main51TxFifoOverflow", Command::Main51TxFifoOverflow)
.value("Main51BulkInNoData", Command::Main51BulkInNoData)
.value("Main51SetModeComplete", Command::Main51SetModeComplete)
.value("Main51ReadEeprom", Command::Main51ReadEeprom)
.value("Main51CmdDone", Command::Main51CmdDone)
.value("Main51ErrStatus", Command::Main51ErrStatus)
.value("Main51ReadSectorBuff", Command::Main51ReadSectorBuff)
.value("Main51WriteSectorBuff", Command::Main51WriteSectorBuff)
.value("Main51MmcProcessDone", Command::Main51MmcProcessDone)
.value("Main51ReInitDone", Command::Main51ReInitDone)
.value("EnableNetworkCommunication", Command::EnableNetworkCommunication)
.value("EnableNetworkCommunicationEx", Command::EnableNetworkCommunicationEx)
.value("KeepAlive", Command::KeepAlive)
.value("RequestSerialNumber", Command::RequestSerialNumber)
.value("GetMainVersion", Command::GetMainVersion)
.value("SetSettings", Command::SetSettings)
.value("SaveSettings", Command::SaveSettings)
.value("SetDefaultSettings", Command::SetDefaultSettings)
.value("ReadSettings", Command::ReadSettings)
.value("ScriptStatus", Command::ScriptStatus)
.value("WiVICommand", Command::WiVICommand)
.value("Extended", Command::Extended)
.value("ExtendedData", Command::ExtendedData)
.value("FlexRayControl", Command::FlexRayControl)
.value("CoreMiniPreload", Command::CoreMiniPreload)
.finalize();
}
} // namespace icsneo
@@ -0,0 +1,13 @@
#include <pybind11/pybind11.h>
#include "icsneo/communication/message/filter/main51messagefilter.h"
namespace icsneo {
void init_main51messagefilter(pybind11::module_& m) {
pybind11::classh<Main51MessageFilter, MessageFilter>(m, "Main51MessageFilter")
.def(pybind11::init<>())
.def(pybind11::init<Command>());
}
} // namespace icsneo
@@ -28,7 +28,8 @@ void init_linmessage(pybind11::module_& m) {
.def_readwrite("UpdateResponderOnce", &LINStatusFlags::UpdateResponderOnce) .def_readwrite("UpdateResponderOnce", &LINStatusFlags::UpdateResponderOnce)
.def_readwrite("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce) .def_readwrite("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce)
.def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered) .def_readwrite("BusRecovered", &LINStatusFlags::BusRecovered)
.def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly); .def_readwrite("BreakOnly", &LINStatusFlags::BreakOnly)
.def_readwrite("WakeupRequest", &LINStatusFlags::WakeupRequest);
pybind11::classh<LINMessage, Frame> linMessage(m, "LINMessage"); pybind11::classh<LINMessage, Frame> linMessage(m, "LINMessage");
@@ -39,7 +40,8 @@ void init_linmessage(pybind11::module_& m) {
.value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY) .value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY)
.value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY) .value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY)
.value("LIN_UPDATE_RESPONDER", LINMessage::Type::LIN_UPDATE_RESPONDER) .value("LIN_UPDATE_RESPONDER", LINMessage::Type::LIN_UPDATE_RESPONDER)
.value("LIN_ERROR", LINMessage::Type::LIN_ERROR); .value("LIN_ERROR", LINMessage::Type::LIN_ERROR)
.value("LIN_WAKEUP_REQUEST", LINMessage::Type::LIN_WAKEUP_REQUEST);
linMessage linMessage
.def(pybind11::init<>()) .def(pybind11::init<>())
@@ -0,0 +1,13 @@
#include <pybind11/pybind11.h>
#include "icsneo/communication/message/main51message.h"
namespace icsneo {
void init_main51message(pybind11::module_& m) {
pybind11::classh<Main51Message, RawMessage>(m, "Main51Message")
.def(pybind11::init<>())
.def_readonly("command", &Main51Message::command);
}
} // namespace icsneo
@@ -154,7 +154,6 @@ void init_macsecconfig(pybind11::module_ & m)
.def("set_storage", &MACsecConfig::setStorage, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("set_storage", &MACsecConfig::setStorage, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("clear", &MACsecConfig::clear, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("clear", &MACsecConfig::clear, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("serialize", &MACsecConfig::serialize, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("serialize", &MACsecConfig::serialize, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_bin_index", &MACsecConfig::getBinIndex, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_type", &MACsecConfig::getType, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_type", &MACsecConfig::getType, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_rule", &MACsecConfig::getMaxNumRule, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_max_num_rule", &MACsecConfig::getMaxNumRule, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_max_num_secy", &MACsecConfig::getMaxNumSecY, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_max_num_secy", &MACsecConfig::getMaxNumSecY, pybind11::call_guard<pybind11::gil_scoped_release>())
+2 -1
View File
@@ -34,6 +34,7 @@ void init_device(pybind11::module_& m) {
.def("get_serial", &Device::getSerial) .def("get_serial", &Device::getSerial)
.def("get_pcb_serial", &Device::getPCBSerial, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_pcb_serial", &Device::getPCBSerial, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_mac_addresses", &Device::getMACAddresses, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_mac_addresses", &Device::getMACAddresses, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_macsec_networks", &Device::getMACsecNetworks)
.def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference) .def("get_supported_rx_networks", &Device::getSupportedRXNetworks, pybind11::return_value_policy::reference)
.def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference) .def("get_supported_tx_networks", &Device::getSupportedTXNetworks, pybind11::return_value_policy::reference)
.def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_tc10_status", &Device::getTC10Status, pybind11::call_guard<pybind11::gil_scoped_release>())
@@ -64,7 +65,7 @@ void init_device(pybind11::module_& m) {
.def("set_value_live_data", &Device::setValueLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("set_value_live_data", &Device::setValueLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("transmit", pybind11::overload_cast<std::shared_ptr<Frame>>(&Device::transmit), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("upload_coremini", [](Device& device, std::string& path, Disk::MemoryType memType) { std::ifstream ifs(path, std::ios::binary); return device.uploadCoremini(ifs, memType); }, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("upload_coremini", [](Device& device, std::string& path, Disk::MemoryType memType) { std::ifstream ifs(path, std::ios::binary); return device.uploadCoremini(ifs, memType); }, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("write_macsec_config", &Device::writeMACsecConfig, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("write_macsec_config", &Device::writeMACsecConfig, pybind11::arg("config"), pybind11::arg("network"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("send_eth_phy_msg", &Device::sendEthPhyMsg, pybind11::arg("message"), pybind11::arg("timeout") = std::chrono::milliseconds(50), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("send_eth_phy_msg", &Device::sendEthPhyMsg, pybind11::arg("message"), pybind11::arg("timeout") = std::chrono::milliseconds(50), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("get_chip_versions", &Device::getChipVersions, pybind11::arg("refreshComponents") = true, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("get_chip_versions", &Device::getChipVersions, pybind11::arg("refreshComponents") = true, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_disk_formatting", &Device::supportsDiskFormatting, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("supports_disk_formatting", &Device::supportsDiskFormatting, pybind11::call_guard<pybind11::gil_scoped_release>())
+6
View File
@@ -32,7 +32,10 @@ void init_deviceextension(pybind11::module_&);
void init_chipid(pybind11::module_&); void init_chipid(pybind11::module_&);
void init_versionreport(pybind11::module_&); void init_versionreport(pybind11::module_&);
void init_device(pybind11::module_&); void init_device(pybind11::module_&);
void init_command(pybind11::module_&);
void init_main51message(pybind11::module_&);
void init_messagefilter(pybind11::module_&); void init_messagefilter(pybind11::module_&);
void init_main51messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&); void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&); void init_version(pybind11::module_&);
void init_flexray(pybind11::module_& m); void init_flexray(pybind11::module_& m);
@@ -69,7 +72,10 @@ PYBIND11_MODULE(icsneopy, m) {
init_scriptstatusmessage(m); init_scriptstatusmessage(m);
init_spimessage(m); init_spimessage(m);
init_livedatamessage(m); init_livedatamessage(m);
init_command(m);
init_main51message(m);
init_messagefilter(m); init_messagefilter(m);
init_main51messagefilter(m);
init_messagecallback(m); init_messagecallback(m);
init_diskdriver(m); init_diskdriver(m);
init_diskdetails(m); init_diskdetails(m);
@@ -137,6 +137,7 @@ static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, c
linpacket->CoreMiniBitsLIN.TXResponder = 1; linpacket->CoreMiniBitsLIN.TXResponder = 1;
break; break;
case LINMessage::Type::LIN_BREAK_ONLY: case LINMessage::Type::LIN_BREAK_ONLY:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
linpacket->CoreMiniBitsLIN.BreakOnly = 1; linpacket->CoreMiniBitsLIN.BreakOnly = 1;
break; break;
default: default:
+24 -3
View File
@@ -20,7 +20,7 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
if( if(
(PhyPacketVersion == pHeader->version) && (PhyPacketVersion == pHeader->version) &&
(sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) && (sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) &&
(numEntries <= MaxPhyEntries) && (numEntries > 0 && numEntries <= MaxPhyEntries) &&
((bytestream.size() - sizeof(PhyRegisterHeader_t)) ((bytestream.size() - sizeof(PhyRegisterHeader_t))
== (sizeof(PhyRegisterPacket_t) * numEntries)) == (sizeof(PhyRegisterPacket_t) * numEntries))
) )
@@ -30,6 +30,10 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
for(size_t entryIdx{0}; entryIdx < numEntries; ++entryIdx) for(size_t entryIdx{0}; entryIdx < numEntries; ++entryIdx)
{ {
const PhyRegisterPacket_t* pEntry = (pFirstEntry + entryIdx); const PhyRegisterPacket_t* pEntry = (pFirstEntry + entryIdx);
if(pEntry->version != PhyPacketVersion) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return nullptr;
}
auto phyMessage = std::make_shared<PhyMessage>(); auto phyMessage = std::make_shared<PhyMessage>();
phyMessage->Enabled = (pEntry->Enabled != 0u); phyMessage->Enabled = (pEntry->Enabled != 0u);
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u); phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
@@ -43,6 +47,10 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
msg->messages.push_back(phyMessage); msg->messages.push_back(phyMessage);
} }
} }
else {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return nullptr;
}
return msg; return msg;
} }
@@ -59,7 +67,20 @@ bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& m
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error); report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
return false; return false;
} }
auto byteSize = (messageCount * sizeof(PhyRegisterPacket_t)) + sizeof(PhyRegisterHeader_t); // Validate every entry before touching the caller's output or submitting a command.
for(const auto& entry : message.messages) {
if(!entry) {
report(APIEvent::Type::RequiredParameterNull, APIEvent::Severity::Error);
return false;
}
if(entry->BusIndex > 15 || entry->Version != PhyPacketVersion ||
(entry->Clause45Enable ? (entry->Clause45.port > FiveBits || entry->Clause45.device > FiveBits) :
(entry->Clause22.phyAddr > FiveBits || entry->Clause22.regAddr > FiveBits))) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return false;
}
}
auto byteSize = bytestream.size() + (messageCount * sizeof(PhyRegisterPacket_t)) + sizeof(PhyRegisterHeader_t);
bytestream.reserve(byteSize); bytestream.reserve(byteSize);
bytestream.push_back(static_cast<uint8_t>(messageCount & 0xFF)); bytestream.push_back(static_cast<uint8_t>(messageCount & 0xFF));
bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF)); bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF));
@@ -67,7 +88,7 @@ bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& m
bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t))); bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t)));
for(auto& phyMessage : message.messages) for(auto& phyMessage : message.messages)
{ {
PhyRegisterPacket_t tempPacket; PhyRegisterPacket_t tempPacket{};
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u; tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u; tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
tempPacket.BusIndex = (phyMessage->BusIndex & 0xF); tempPacket.BusIndex = (phyMessage->BusIndex & 0xF);
+17 -5
View File
@@ -72,18 +72,30 @@ std::shared_ptr<Message> HardwareLINPacket::DecodeToMessage(const std::vector<ui
static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce), static_cast<bool>(packet->CoreMiniBitsLIN.UpdateResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce), static_cast<bool>(packet->CoreMiniBitsLIN.HasUpdatedResponderOnce),
static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered), static_cast<bool>(packet->CoreMiniBitsLIN.BusRecovered),
static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly) static_cast<bool>(packet->CoreMiniBitsLIN.BreakOnly),
static_cast<bool>(packet->CoreMiniBitsLIN.WakeupRequest)
}; };
if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder) // Wake type only for a wake-only pulse. A UART/LIN break or a complete
// frame may also carry WakeupRequest; those keep their existing type.
const bool wakeupPulse = msg->statusFlags.WakeupRequest &&
packet->CoreMiniBitsLIN.len == 0 &&
packet->CoreMiniBitsLIN.ID == 0 &&
!msg->statusFlags.BreakOnly &&
!msg->errFlags.ErrRxBreakOnly &&
!msg->errFlags.ErrRxBreakSyncOnly;
if(wakeupPulse)
msg->linMsgType = LINMessage::Type::LIN_WAKEUP_REQUEST;
else if(msg->statusFlags.TxCommander || msg->statusFlags.TxResponder)
msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG; msg->linMsgType = LINMessage::Type::LIN_COMMANDER_MSG;
else if(msg->statusFlags.BreakOnly) else if(msg->statusFlags.BreakOnly)
msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY; msg->linMsgType = LINMessage::Type::LIN_BREAK_ONLY;
if( msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly || if( !wakeupPulse &&
(msg->errFlags.ErrRxBreakOnly || msg->errFlags.ErrRxBreakSyncOnly ||
msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero || msg->errFlags.ErrTxRxMismatch || msg->errFlags.ErrRxBreakNotZero ||
msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 || msg->errFlags.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 ||
msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync || msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync ||
msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch || msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch ||
msg->errFlags.ErrFrameResponderData ) msg->errFlags.ErrFrameResponderData) )
{ msg->linMsgType = LINMessage::Type::LIN_ERROR; } { msg->linMsgType = LINMessage::Type::LIN_ERROR; }
msg->timestamp = packet->timestamp; msg->timestamp = packet->timestamp;
@@ -103,7 +115,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
} }
case LINMessage::Type::LIN_BREAK_ONLY: case LINMessage::Type::LIN_BREAK_ONLY:
{ {
size |= 0x20u; size |= 0x80u | 0x20u;
break; break;
} }
case LINMessage::Type::NOT_SET: case LINMessage::Type::NOT_SET:
+2 -6
View File
@@ -231,16 +231,16 @@ MACsecConfig::MACsecConfig(const DeviceType& deviceType) : type(deviceType) {
case icsneo::DeviceType::Enum::RADMoon3: case icsneo::DeviceType::Enum::RADMoon3:
case icsneo::DeviceType::Enum::RADEpsilon: case icsneo::DeviceType::Enum::RADEpsilon:
case icsneo::DeviceType::Enum::RADGigastar2: case icsneo::DeviceType::Enum::RADGigastar2:
case icsneo::DeviceType::Enum::RADComet2:
case icsneo::DeviceType::Enum::RADComet3:
maxSecY = 2; maxSecY = 2;
maxRule = 2; maxRule = 2;
maxSa = 4; maxSa = 4;
binIndex = 0;
break; break;
default: default:
maxSecY = 0; maxSecY = 0;
maxSa = 0; maxSa = 0;
maxRule = 0; maxRule = 0;
binIndex = 0;
ReportEvent(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error); ReportEvent(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return; return;
} }
@@ -515,10 +515,6 @@ MACsecConfig::operator bool() const {
return (maxSa != 0) || (maxSecY != 0) || (maxRule != 0); return (maxSa != 0) || (maxSecY != 0) || (maxRule != 0);
} }
uint16_t MACsecConfig::getBinIndex() const {
return binIndex;
}
DeviceType MACsecConfig::getType() const { DeviceType MACsecConfig::getType() const {
return type; return type;
} }
+23 -3
View File
@@ -2053,7 +2053,12 @@ std::optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message,
} }
std::vector<uint8_t> bytes; std::vector<uint8_t> bytes;
HardwareEthernetPhyRegisterPacket::EncodeFromMessage(message, bytes, report); if(timeout.count() <= 0) {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return std::nullopt;
}
if(!HardwareEthernetPhyRegisterPacket::EncodeFromMessage(message, bytes, report))
return std::nullopt;
std::shared_ptr<Message> response = com->waitForMessageSync( std::shared_ptr<Message> response = com->waitForMessageSync(
[this, bytes](){ return com->sendCommand(Command::PHYControlRegisters, bytes); }, [this, bytes](){ return com->sendCommand(Command::PHYControlRegisters, bytes); },
std::make_shared<MessageFilter>(Message::Type::EthernetPhyRegister), timeout); std::make_shared<MessageFilter>(Message::Type::EthernetPhyRegister), timeout);
@@ -3761,7 +3766,15 @@ std::optional<GPTPStatus> Device::getGPTPStatus(std::chrono::milliseconds timeou
return *retMsg; return *retMsg;
} }
bool Device::writeMACsecConfig(const MACsecConfig& cfg) { std::vector<Network> Device::getMACsecNetworks() const {
std::vector<Network> networks;
for(const auto& network : getMACsecNetworkMap()) {
networks.emplace_back(network.first);
}
return networks;
}
bool Device::writeMACsecConfig(const MACsecConfig& cfg, Network::NetID network) {
if(!cfg) { if(!cfg) {
report(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error); report(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return false; return false;
@@ -3772,8 +3785,15 @@ bool Device::writeMACsecConfig(const MACsecConfig& cfg) {
return false; return false;
} }
const auto& networks = getMACsecNetworkMap();
const auto binaryIndex = networks.find(network);
if(binaryIndex == networks.end()) {
report(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return false;
}
std::vector<uint8_t> raw = cfg.serialize(); std::vector<uint8_t> raw = cfg.serialize();
return writeBinaryFile(raw, cfg.getBinIndex()); return writeBinaryFile(raw, binaryIndex->second);
} }
bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) { bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) {
+1 -1
View File
@@ -77,7 +77,7 @@ int main(int, char**) {
cfg.setTxEnable(true); cfg.setTxEnable(true);
// Write config to the device // Write config to the device
if(!device->writeMACsecConfig(cfg)) { if(!device->writeMACsecConfig(cfg, icsneo::Network::NetID::AE_01)) {
std::cout << "Failed to write MACsec config" << std::endl; std::cout << "Failed to write MACsec config" << std::endl;
std::cout << icsneo::GetLastError() << std::endl; std::cout << icsneo::GetLastError() << std::endl;
return -1; return -1;
+45
View File
@@ -0,0 +1,45 @@
import icsneopy
import time
#
# Main51 messages are device-originated notifications from the firmware's Main51 processor.
# This example filters for RX buffer overflow and TX FIFO overflow events.
#
def main51_filter():
devices = icsneopy.find_all_devices()
if len(devices) == 0:
print("no devices found")
return False
device = devices[0]
print(f"selected {device}")
def on_main51(message):
if not isinstance(message, icsneopy.Main51Message):
return
if message.command == icsneopy.Command.Main51RxBufferOverflow:
print("RX buffer overflow")
elif message.command == icsneopy.Command.Main51TxFifoOverflow:
print("TX FIFO overflow")
else:
print(f"Main51 command: {message.command}")
filter = icsneopy.Main51MessageFilter()
callback = icsneopy.MessageCallback(on_main51, filter)
device.add_message_callback(callback)
if not device.open():
print("unable to open device")
return False
if not device.go_online():
print("unable to go online")
return False
time.sleep(5)
return True
if __name__ == "__main__":
main51_filter()
@@ -17,13 +17,13 @@ namespace icsneo {
#endif #endif
struct PhyMessage { struct PhyMessage {
bool Enabled; bool Enabled = false;
bool WriteEnable; bool WriteEnable = false;
bool Clause45Enable; bool Clause45Enable = false;
uint8_t BusIndex; uint8_t BusIndex = 0;
uint8_t Version; uint8_t Version = PhyPacketVersion;
union { union {
Clause22Message Clause22; Clause22Message Clause22{};
Clause45Message Clause45; Clause45Message Clause45;
}; };
}; };
@@ -34,6 +34,7 @@ struct LINStatusFlags {
bool HasUpdatedResponderOnce = false; bool HasUpdatedResponderOnce = false;
bool BusRecovered = false; bool BusRecovered = false;
bool BreakOnly = false; bool BreakOnly = false;
bool WakeupRequest = false;
}; };
class LINMessage : public Frame { class LINMessage : public Frame {
@@ -45,7 +46,8 @@ public:
LIN_BREAK_ONLY = icsneoc2_lin_msg_type_break_only, LIN_BREAK_ONLY = icsneoc2_lin_msg_type_break_only,
LIN_SYNC_ONLY = icsneoc2_lin_msg_type_sync_only, LIN_SYNC_ONLY = icsneoc2_lin_msg_type_sync_only,
LIN_UPDATE_RESPONDER = icsneoc2_lin_msg_type_update_responder, LIN_UPDATE_RESPONDER = icsneoc2_lin_msg_type_update_responder,
LIN_ERROR = icsneoc2_lin_msg_type_error LIN_ERROR = icsneoc2_lin_msg_type_error,
LIN_WAKEUP_REQUEST = icsneoc2_lin_msg_type_wakeup_request
}; };
static void calcChecksum(LINMessage& message); static void calcChecksum(LINMessage& message);
@@ -65,7 +65,7 @@ struct PhyRegisterPacket_t {
#pragma pack(pop) #pragma pack(pop)
static constexpr size_t MaxPhyEntries = 128u; static constexpr size_t MaxPhyEntries = 128u;
static constexpr size_t MaxBytesPhyEntries = MaxPhyEntries * sizeof(PhyRegisterHeader_t); static constexpr size_t MaxBytesPhyEntries = MaxPhyEntries * sizeof(PhyRegisterPacket_t);
static constexpr uint8_t PhyPacketVersion = 1u; static constexpr uint8_t PhyPacketVersion = 1u;
static constexpr uint8_t FiveBits = 0x1Fu; static constexpr uint8_t FiveBits = 0x1Fu;
@@ -47,7 +47,8 @@ struct HardwareLINPacket {
uint16_t ResponderByteFerr : 1; //Framing error in one of our responder bytes. uint16_t ResponderByteFerr : 1; //Framing error in one of our responder bytes.
uint16_t TxAborted : 1;//!< This transmit was aborted. uint16_t TxAborted : 1;//!< This transmit was aborted.
uint16_t BreakOnly : 1; uint16_t BreakOnly : 1;
uint16_t : 2; uint16_t WakeupRequest : 1; //!< LIN wakeup pulse.
uint16_t : 1;
} CoreMiniBitsLIN; } CoreMiniBitsLIN;
uint8_t data[8]; uint8_t data[8];
-2
View File
@@ -150,7 +150,6 @@ private:
uint8_t maxSecY; uint8_t maxSecY;
uint8_t maxSa; uint8_t maxSa;
uint8_t maxRule; uint8_t maxRule;
uint16_t binIndex;
DeviceType type; DeviceType type;
std::vector<MACsecRxRule> rxRule; std::vector<MACsecRxRule> rxRule;
@@ -205,7 +204,6 @@ public:
void clear(); void clear();
std::vector<uint8_t> serialize() const; std::vector<uint8_t> serialize() const;
operator bool() const; operator bool() const;
uint16_t getBinIndex() const;
DeviceType getType() const; DeviceType getType() const;
uint8_t getMaxNumRule() const; uint8_t getMaxNumRule() const;
uint8_t getMaxNumSecY() const; uint8_t getMaxNumSecY() const;
+10 -1
View File
@@ -12,6 +12,7 @@
#include <type_traits> #include <type_traits>
#include <optional> #include <optional>
#include <unordered_map> #include <unordered_map>
#include <map>
#include <set> #include <set>
#include <unordered_set> #include <unordered_set>
#include <chrono> #include <chrono>
@@ -897,7 +898,8 @@ public:
std::optional<GPTPStatus> getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100)); std::optional<GPTPStatus> getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100));
/* MACsec support */ /* MACsec support */
virtual bool writeMACsecConfig(const MACsecConfig& cfg); std::vector<Network> getMACsecNetworks() const;
bool writeMACsecConfig(const MACsecConfig& cfg, Network::NetID network);
std::shared_ptr<DeviceExtension> getExtension(const std::string& name) const; std::shared_ptr<DeviceExtension> getExtension(const std::string& name) const;
@@ -917,6 +919,13 @@ public:
bool iso15765SetupRxFlowControl(const Network& network, const Iso15765MessageArgs& msg); bool iso15765SetupRxFlowControl(const Network& network, const Iso15765MessageArgs& msg);
protected: protected:
using MACsecNetworkMap = std::map<Network::NetID, uint16_t>;
virtual const MACsecNetworkMap& getMACsecNetworkMap() const {
static const MACsecNetworkMap networks;
return networks;
}
bool online = false; bool online = false;
int messagePollingCallbackID = 0; int messagePollingCallbackID = 0;
int internalHandlerCallbackID = 0; int internalHandlerCallbackID = 0;
@@ -132,9 +132,8 @@ protected:
virtual void setupExtensions() override { virtual void setupExtensions() override {
std::vector<Network> flexRayControllers; std::vector<Network> flexRayControllers;
flexRayControllers.push_back(Network::NetID::FLEXRAY_01); flexRayControllers.push_back(Network::NetID::FLEXRAY_01);
flexRayControllers.push_back(Network::NetID::FLEXRAY_01); flexRayControllers.push_back(Network::NetID::FLEXRAY_02);
addExtension(std::make_shared<FlexRay::Extension>(*this, flexRayControllers)); addExtension(std::make_shared<FlexRay::Extension>(*this, flexRayControllers));
} }
virtual std::vector<std::shared_ptr<FlexRay::Controller>> getFlexRayControllers() const override { virtual std::vector<std::shared_ptr<FlexRay::Controller>> getFlexRayControllers() const override {
@@ -70,6 +70,13 @@ public:
} }
protected: protected:
const MACsecNetworkMap& getMACsecNetworkMap() const override {
static const MACsecNetworkMap networks = {
{Network::NetID::AE_01, 0},
};
return networks;
}
RADComet2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADComet2(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADComet2Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<RADComet2Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
@@ -118,6 +118,18 @@ public:
} }
} }
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radcomet2_settings_t>();
if(cfg == nullptr)
return nullptr;
switch(net.getNetID()) {
case Network::NetID::LIN_01:
return &(cfg->lin1);
default:
return nullptr;
}
}
std::optional<bool> isT1SPLCAEnabledFor(Network net) const override { std::optional<bool> isT1SPLCAEnabledFor(Network net) const override {
const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net); const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net);
if(t1s == nullptr) if(t1s == nullptr)
@@ -77,6 +77,13 @@ public:
} }
protected: protected:
const MACsecNetworkMap& getMACsecNetworkMap() const override {
static const MACsecNetworkMap networks = {
{Network::NetID::AE_01, 0},
};
return networks;
}
RADComet3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADComet3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADComet3Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<RADComet3Settings, Disk::NeoMemoryDiskDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
} }
@@ -115,6 +115,18 @@ public:
} }
} }
const LIN_SETTINGS* getLINSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radcomet3_settings_t>();
if(cfg == nullptr)
return nullptr;
switch(net.getNetID()) {
case Network::NetID::LIN_01:
return &(cfg->lin1);
default:
return nullptr;
}
}
const ETHERNET_SETTINGS2* getEthernetSettingsFor(Network net) const override { const ETHERNET_SETTINGS2* getEthernetSettingsFor(Network net) const override {
auto cfg = getStructurePointer<radcomet3_settings_t>(); auto cfg = getStructurePointer<radcomet3_settings_t>();
if(cfg == nullptr) if(cfg == nullptr)
@@ -217,6 +217,14 @@ public:
return chipVersions; return chipVersions;
} }
protected: protected:
const MACsecNetworkMap& getMACsecNetworkMap() const override {
static const MACsecNetworkMap networks = {
{Network::NetID::AE_01, 0},
{Network::NetID::AE_02, 1},
};
return networks;
}
RADGigastar2(neodevice_t neodevice, const driver_factory_t &makeDriver) : Device(neodevice) RADGigastar2(neodevice_t neodevice, const driver_factory_t &makeDriver) : Device(neodevice)
{ {
initialize<RADGigastar2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver); initialize<RADGigastar2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
@@ -38,6 +38,13 @@ public:
.add<ReconnectPhase>(); .add<ReconnectPhase>();
} }
protected: protected:
const MACsecNetworkMap& getMACsecNetworkMap() const override {
static const MACsecNetworkMap networks = {
{Network::NetID::AE_01, 0},
};
return networks;
}
RADMoon2ZL(neodevice_t neodevice, const driver_factory_t& makeDriver) : RADMoon2Base(neodevice) { RADMoon2ZL(neodevice_t neodevice, const driver_factory_t& makeDriver) : RADMoon2Base(neodevice) {
initialize<RADMoon2Settings>(makeDriver); initialize<RADMoon2Settings>(makeDriver);
} }
@@ -52,6 +52,14 @@ public:
.add<ReconnectPhase>(); .add<ReconnectPhase>();
} }
protected: protected:
const MACsecNetworkMap& getMACsecNetworkMap() const override {
static const MACsecNetworkMap networks = {
{Network::NetID::AE_01, 0},
{Network::NetID::ETHERNET_01, 1},
};
return networks;
}
RADMoon3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) { RADMoon3(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADMoon3Settings>(makeDriver); initialize<RADMoon3Settings>(makeDriver);
} }
+2
View File
@@ -381,6 +381,7 @@ typedef enum _icsneoc2_lin_msg_type_t {
icsneoc2_lin_msg_type_sync_only = 4, icsneoc2_lin_msg_type_sync_only = 4,
icsneoc2_lin_msg_type_update_responder = 5, icsneoc2_lin_msg_type_update_responder = 5,
icsneoc2_lin_msg_type_error = 6, icsneoc2_lin_msg_type_error = 6,
icsneoc2_lin_msg_type_wakeup_request = 7,
} _icsneoc2_lin_msg_type_t; } _icsneoc2_lin_msg_type_t;
typedef uint8_t icsneoc2_lin_msg_type_t; typedef uint8_t icsneoc2_lin_msg_type_t;
@@ -409,6 +410,7 @@ typedef uint32_t icsneoc2_lin_err_flags_t;
#define ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE 0x20 #define ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE 0x20
#define ICSNEOC2_LIN_STATUS_BUS_RECOVERED 0x40 #define ICSNEOC2_LIN_STATUS_BUS_RECOVERED 0x40
#define ICSNEOC2_LIN_STATUS_BREAK_ONLY 0x80 #define ICSNEOC2_LIN_STATUS_BREAK_ONLY 0x80
#define ICSNEOC2_LIN_STATUS_WAKEUP_REQUEST 0x100
typedef uint32_t icsneoc2_lin_status_flags_t; typedef uint32_t icsneoc2_lin_status_flags_t;
+103
View File
@@ -0,0 +1,103 @@
#include "icsneo/communication/message/ethphymessage.h"
#include "icsneo/communication/packet/ethphyregpacket.h"
#include "gtest/gtest.h"
#include "icsneo/device/tree/radjupiter/radjupiter.h"
using namespace icsneo;
namespace {
const device_eventhandler_t ignore = [](APIEvent::Type, APIEvent::Severity) {};
EthPhyMessage request(bool clause45 = false, bool write = false) {
EthPhyMessage msg;
msg.appendPhyMessage(write, clause45, 31, clause45 ? 31 : 255, clause45 ? 65535 : 31, 0x1234);
msg.messages[0]->BusIndex = 15;
return msg;
}
std::vector<uint8_t> encode(const EthPhyMessage& msg) {
std::vector<uint8_t> bytes;
EXPECT_TRUE(HardwareEthernetPhyRegisterPacket::EncodeFromMessage(msg, bytes, ignore));
return bytes;
}
}
TEST(EthPhyRegister, KnownWireBytes) {
for(bool clause45 : {false, true}) {
auto msg = request(clause45, true);
auto bytes = encode(msg);
EXPECT_EQ(bytes, (std::vector<uint8_t>{1, 0, 1, 8, static_cast<uint8_t>(clause45 ? 7 : 3), 0x1f,
31, static_cast<uint8_t>(clause45 ? 31 : 255), static_cast<uint8_t>(clause45 ? 255 : 31),
static_cast<uint8_t>(clause45 ? 255 : 0), 0x34, 0x12}));
}
}
TEST(EthPhyRegister, InvalidRequestsLeaveOutputUntouched) {
for(int invalid = 0; invalid < 8; ++invalid) {
auto msg = request();
switch(invalid) {
case 0: msg.messages.clear(); break;
case 1: msg.messages.resize(129, msg.messages[0]); break;
case 2: msg.messages.push_back(nullptr); break;
case 3: msg.messages[0]->BusIndex = 16; break;
case 4: msg.messages[0]->Version = 0; break;
case 5: msg.messages[0]->Clause22.phyAddr = 32; break;
case 6: msg.messages[0]->Clause22.regAddr = 32; break;
case 7: msg.messages = request(true).messages; msg.messages[0]->Clause45.device = 32; break;
}
std::vector<uint8_t> bytes{0xaa};
EXPECT_FALSE(HardwareEthernetPhyRegisterPacket::EncodeFromMessage(msg, bytes, ignore));
EXPECT_EQ(bytes, (std::vector<uint8_t>{0xaa}));
}
auto msg = request(); msg.messages.resize(128, msg.messages[0]);
EXPECT_EQ(encode(msg).size(), 1028u);
}
TEST(EthPhyRegister, RejectMalformedResponses) {
const auto valid = encode(request());
for(size_t size = 0; size < valid.size(); ++size)
EXPECT_EQ(HardwareEthernetPhyRegisterPacket::DecodeToMessage({valid.begin(), valid.begin() + size}, ignore), nullptr);
for(size_t index : {0u, 2u, 3u, 5u}) {
auto bytes = valid; bytes[index] = 0;
EXPECT_EQ(HardwareEthernetPhyRegisterPacket::DecodeToMessage(bytes, ignore), nullptr);
}
auto extra = valid; extra.push_back(0);
EXPECT_EQ(HardwareEthernetPhyRegisterPacket::DecodeToMessage(extra, ignore), nullptr);
}
namespace {
class PhyTestDriver : public Driver {
public:
explicit PhyTestDriver(const device_eventhandler_t& report) : Driver(report) {}
bool open() override { return false; }
bool isOpen() override { return opened; }
bool opened = true;
bool close() override { opened = false; return true; }
driver_finder_t getFinder() override { return [](std::vector<FoundDevice>&) {}; }
int writes = 0;
protected:
bool writeInternal(const std::vector<uint8_t>&) override { ++writes; return false; }
};
class PhyTestJupiter : public RADJupiter {
public:
explicit PhyTestJupiter(const FoundDevice& found) : RADJupiter(found) {}
~PhyTestJupiter() override { com->driver->close(); }
bool isOpen() const override { return true; } // Exercise the native send path, without hardware.
};
}
TEST(EthPhyRegister, DeviceDoesNotSendInvalidRequests) {
PhyTestDriver* driver = nullptr;
FoundDevice found;
found.makeDriver = [&driver](device_eventhandler_t report, neodevice_t&) {
auto result = std::make_unique<PhyTestDriver>(report);
driver = result.get();
return result;
};
PhyTestJupiter device(found);
auto msg = request();
msg.messages.push_back(nullptr);
EXPECT_FALSE(device.sendEthPhyMsg(msg).has_value());
EXPECT_EQ(driver->writes, 0);
msg.messages = request().messages; msg.messages[0]->BusIndex = 16;
EXPECT_FALSE(device.sendEthPhyMsg(msg).has_value());
EXPECT_EQ(driver->writes, 0);
msg.messages = request().messages;
EXPECT_FALSE(device.sendEthPhyMsg(msg, std::chrono::milliseconds(0)).has_value());
EXPECT_EQ(driver->writes, 0);
// The valid request reaches the fake driver's explicit send failure.
EXPECT_FALSE(device.sendEthPhyMsg(msg).has_value());
EXPECT_EQ(driver->writes, 1);
}
+3
View File
@@ -1862,6 +1862,7 @@ TEST(icsneoc2, test_lin_msg_type_enum_values)
ASSERT_EQ(icsneoc2_lin_msg_type_sync_only, 4); ASSERT_EQ(icsneoc2_lin_msg_type_sync_only, 4);
ASSERT_EQ(icsneoc2_lin_msg_type_update_responder, 5); ASSERT_EQ(icsneoc2_lin_msg_type_update_responder, 5);
ASSERT_EQ(icsneoc2_lin_msg_type_error, 6); ASSERT_EQ(icsneoc2_lin_msg_type_error, 6);
ASSERT_EQ(icsneoc2_lin_msg_type_wakeup_request, 7);
ASSERT_EQ(sizeof(icsneoc2_lin_msg_type_t), sizeof(uint8_t)); ASSERT_EQ(sizeof(icsneoc2_lin_msg_type_t), sizeof(uint8_t));
} }
@@ -1875,6 +1876,7 @@ TEST(icsneoc2, test_lin_msg_type_cpp_enum_sync)
ASSERT_EQ(static_cast<uint8_t>(T::LIN_SYNC_ONLY), icsneoc2_lin_msg_type_sync_only); ASSERT_EQ(static_cast<uint8_t>(T::LIN_SYNC_ONLY), icsneoc2_lin_msg_type_sync_only);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_UPDATE_RESPONDER), icsneoc2_lin_msg_type_update_responder); ASSERT_EQ(static_cast<uint8_t>(T::LIN_UPDATE_RESPONDER), icsneoc2_lin_msg_type_update_responder);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_ERROR), icsneoc2_lin_msg_type_error); ASSERT_EQ(static_cast<uint8_t>(T::LIN_ERROR), icsneoc2_lin_msg_type_error);
ASSERT_EQ(static_cast<uint8_t>(T::LIN_WAKEUP_REQUEST), icsneoc2_lin_msg_type_wakeup_request);
} }
TEST(icsneoc2, test_lin_flag_bitmask_values) TEST(icsneoc2, test_lin_flag_bitmask_values)
@@ -1901,6 +1903,7 @@ TEST(icsneoc2, test_lin_flag_bitmask_values)
ASSERT_EQ(ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE, 0x20); ASSERT_EQ(ICSNEOC2_LIN_STATUS_HAS_UPDATED_RESPONDER_ONCE, 0x20);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_BUS_RECOVERED, 0x40); ASSERT_EQ(ICSNEOC2_LIN_STATUS_BUS_RECOVERED, 0x40);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_BREAK_ONLY, 0x80); ASSERT_EQ(ICSNEOC2_LIN_STATUS_BREAK_ONLY, 0x80);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_WAKEUP_REQUEST, 0x100);
} }
TEST(icsneoc2, test_icsneoc2_eth_create) TEST(icsneoc2, test_icsneoc2_eth_create)
+77
View File
@@ -2,12 +2,14 @@
#include "icsneo/communication/encoder.h" #include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/linpacket.h" #include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/linmessage.h" #include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/transmitmessage.h"
#include "icsneo/communication/packetizer.h" #include "icsneo/communication/packetizer.h"
#include "icsneo/core/ringbuffer.h" #include "icsneo/core/ringbuffer.h"
#include "icsneo/api/eventmanager.h" #include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <cstring>
using namespace icsneo; using namespace icsneo;
@@ -55,6 +57,16 @@ protected:
0x00, 0x00, 0x00, 0x00,
0xE2, 0x41}; 0xE2, 0x41};
// Break-only LIN 1: commander (0x80) | break-only (0x20) | len 3 => 0xa3
// ID 0x00 pID 0x80
std::vector<uint8_t> testControllerBreakOnly =
{0xaa, 0x0c,
0x0d, 0x00,
0x10, 0x00,
0x00, 0xa3,
0x00, 0x00,
0x80, 0x41};
std::vector<uint8_t> recvBytes = std::vector<uint8_t> recvBytes =
{0xaa, 0x0c, 0x22, 0x00, {0xaa, 0x0c, 0x22, 0x00,
0x10, 0x00, 0x88, 0x03, 0x10, 0x00, 0x88, 0x03,
@@ -139,6 +151,29 @@ TEST_F(LINEncoderDecoderTest, PacketEncoderControllerHeaderTest) {
EXPECT_EQ(bytestream, testControllerHeaderOnly); EXPECT_EQ(bytestream, testControllerHeaderOnly);
} }
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerBreakOnlyTest) {
std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
message->network = icsneo::Network::NetID::LIN_01;
message->linMsgType = icsneo::LINMessage::Type::LIN_BREAK_ONLY;
message->isEnhancedChecksum = false;
packetEncoder->encode(*packetizer, bytestream, message);
EXPECT_EQ(bytestream, testControllerBreakOnly);
}
TEST_F(LINEncoderDecoderTest, TransmitMessageBreakOnlySetsCommander) {
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x00u));
message->network = icsneo::Network::NetID::LIN_01;
message->linMsgType = icsneo::LINMessage::Type::LIN_BREAK_ONLY;
auto bytes = TransmitMessage::EncodeFromMessage(message, 1, report);
ASSERT_FALSE(bytes.empty());
ASSERT_GE(bytes.size(), sizeof(TransmitMessage));
auto* tx = reinterpret_cast<TransmitMessage*>(bytes.data());
auto* lin = reinterpret_cast<HardwareLINPacket*>(tx->commonHeader);
EXPECT_EQ(lin->CoreMiniBitsLIN.TXCommander, 1);
EXPECT_EQ(lin->CoreMiniBitsLIN.BreakOnly, 1);
}
TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWithDataTest) { TEST_F(LINEncoderDecoderTest, PacketEncoderControllerWithDataTest) {
std::vector<uint8_t> bytestream; std::vector<uint8_t> bytestream;
auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x11u)); auto message = std::make_shared<icsneo::LINMessage>(static_cast<uint8_t>(0x11u));
@@ -193,3 +228,45 @@ TEST_F(LINEncoderDecoderTest, PacketDecoderTest) {
EXPECT_EQ(msg2->data, testMessage2->data); EXPECT_EQ(msg2->data, testMessage2->data);
EXPECT_EQ(msg2->checksum, testMessage2->checksum); EXPECT_EQ(msg2->checksum, testMessage2->checksum);
} }
static std::shared_ptr<LINMessage> decodeLinPacket(const HardwareLINPacket& pkt) {
std::vector<uint8_t> bytes(sizeof(pkt));
std::memcpy(bytes.data(), &pkt, sizeof(pkt));
return std::dynamic_pointer_cast<LINMessage>(HardwareLINPacket::DecodeToMessage(bytes));
}
TEST_F(LINEncoderDecoderTest, WakeupPulseDecodeTest) {
HardwareLINPacket pkt{};
pkt.CoreMiniBitsLIN.WakeupRequest = 1;
auto msg = decodeLinPacket(pkt);
ASSERT_NE(msg, nullptr);
EXPECT_EQ(msg->linMsgType, LINMessage::Type::LIN_WAKEUP_REQUEST);
EXPECT_TRUE(msg->statusFlags.WakeupRequest);
}
TEST_F(LINEncoderDecoderTest, WakeupFlagOnUartBreakStaysError) {
HardwareLINPacket pkt{};
pkt.CoreMiniBitsLIN.WakeupRequest = 1;
pkt.CoreMiniBitsLIN.ErrRxOnlyBreak = 1;
auto msg = decodeLinPacket(pkt);
ASSERT_NE(msg, nullptr);
EXPECT_EQ(msg->linMsgType, LINMessage::Type::LIN_ERROR);
EXPECT_TRUE(msg->statusFlags.WakeupRequest);
EXPECT_TRUE(msg->errFlags.ErrRxBreakOnly);
}
TEST_F(LINEncoderDecoderTest, WakeupFlagOnCompleteFrameKeepsCommander) {
HardwareLINPacket pkt{};
pkt.CoreMiniBitsLIN.WakeupRequest = 1;
pkt.CoreMiniBitsLIN.TXCommander = 1;
pkt.CoreMiniBitsLIN.ID = 0x10;
pkt.CoreMiniBitsLIN.len = 3; // two responder bytes plus the checksum
pkt.data[0] = 0xaa;
pkt.data[1] = 0xbb;
pkt.data[2] = 0x99; // classic checksum, otherwise the frame decodes as LIN_ERROR
auto msg = decodeLinPacket(pkt);
ASSERT_NE(msg, nullptr);
EXPECT_EQ(msg->linMsgType, LINMessage::Type::LIN_COMMANDER_MSG);
EXPECT_TRUE(msg->statusFlags.WakeupRequest);
EXPECT_EQ(msg->ID, 0x10);
}
+84
View File
@@ -0,0 +1,84 @@
#include <gtest/gtest.h>
#include <cstring>
#include "icsneo/communication/driver.h"
#include "icsneo/core/macseccfg.h"
#include "icsneo/disk/neomemorydiskdriver.h"
#include "icsneo/device/tree/radcomet2/radcomet2.h"
#include "icsneo/device/tree/radcomet3/radcomet3.h"
#include "icsneo/device/tree/radgigastar2/radgigastar2.h"
#include "icsneo/device/tree/radmoon2/radmoon2.h"
#include "icsneo/device/tree/radmoon2/radmoon2zl.h"
#include "icsneo/device/tree/radmoon3/radmoon3.h"
using namespace icsneo;
namespace {
class MACsecTestDriver : public Driver {
public:
MACsecTestDriver(const device_eventhandler_t& handler) : Driver(handler) {}
bool open() override { return true; }
bool isOpen() override { return true; }
bool close() override { return true; }
driver_finder_t getFinder() override {
return [](std::vector<FoundDevice>&) {};
}
};
FoundDevice makeFoundDevice(const char* serial) {
FoundDevice found;
std::memcpy(found.serial, serial, sizeof(found.serial) - 1);
found.serial[sizeof(found.serial) - 1] = '\0';
found.makeDriver = [](device_eventhandler_t handler, neodevice_t&) {
return std::make_unique<MACsecTestDriver>(handler);
};
return found;
}
std::vector<Network::NetID> getMACsecNetIDs(const Device& device) {
std::vector<Network::NetID> netIDs;
for(const auto& network : device.getMACsecNetworks())
netIDs.push_back(network.getNetID());
return netIDs;
}
TEST(MACsec, RADMoon2ZLOnlyMapsAutomotiveEthernet) {
RADMoon2 moon2(makeFoundDevice("RM0001"));
RADMoon2ZL moon2zl(makeFoundDevice("RN0001"));
EXPECT_TRUE(getMACsecNetIDs(moon2).empty());
EXPECT_EQ(getMACsecNetIDs(moon2zl), std::vector<Network::NetID>({Network::NetID::AE_01}));
}
TEST(MACsec, RADMoon3MapsIndependentPHYs) {
RADMoon3 moon3(makeFoundDevice("R30001"));
EXPECT_EQ(
getMACsecNetIDs(moon3),
std::vector<Network::NetID>({Network::NetID::AE_01, Network::NetID::ETHERNET_01})
);
}
TEST(MACsec, RADGigastar2MapsBothMACsecPorts) {
RADGigastar2 gigastar2(makeFoundDevice("GT0001"));
EXPECT_EQ(
getMACsecNetIDs(gigastar2),
std::vector<Network::NetID>({Network::NetID::AE_01, Network::NetID::AE_02})
);
}
TEST(MACsec, RADCometsMapOneMACsecPort) {
RADComet2 comet2(makeFoundDevice("RC0300"));
RADComet3 comet3(makeFoundDevice("C30001"));
EXPECT_EQ(getMACsecNetIDs(comet2), std::vector<Network::NetID>({Network::NetID::AE_01}));
EXPECT_EQ(getMACsecNetIDs(comet3), std::vector<Network::NetID>({Network::NetID::AE_01}));
EXPECT_TRUE(MACsecConfig(comet2.getType()));
EXPECT_TRUE(MACsecConfig(comet3.getType()));
}
} // namespace