19 Commits
Author SHA1 Message Date
Max BrombachandKyle Schwarz 3932b54947 Device: RAD-Gigastar and RAD-Gigastar 2: Fix bootloader pipeline 2026-10-02 14:28:40 -04:00
Nicholas ZamoraandKyle Schwarz f4836f279f Device: RAD-Gemini to RAD-Argos 2026-10-02 13:53:55 -04:00
Thomas StoddardandKyle Schwarz 7ef57e6737 Device: Improve TC10 message filtering 2026-09-30 13:07:13 -04:00
David RebbeandKyle Schwarz 4c0781190e Message: EthPhyMessage: Add Status 2026-09-29 15:01:36 -04:00
Kyle Schwarz 0a67c9cf5d Platform: Servd: Add address configuration 2026-09-28 12:02:40 -04:00
David RebbeandKyle Schwarz f310938684 Message: Validate PHY register batches 2026-09-24 20:13:48 -04:00
Thomas StoddardandKyle Schwarz f0b1341cdf Device: Write MACsec configs by network ID 2026-09-24 19:49:23 -04:00
Max BrombachandKyle Schwarz b54bf80c40 EventManager: Always run callbacks on event 2026-09-24 13:26:13 -04:00
Bryant JonesandKyle Schwarz 0164cef376 NeoVIFIRE3FlexRay: Fix incorrect FlexRay controllers 2026-09-23 16:46:37 -04:00
Thomas StoddardandKyle Schwarz 8cd907250d Bindings: Python: Add Main51MessageFilter support 2026-09-21 13:39:27 -04:00
David RebbeandKyle Schwarz bb892bfd9b Bindings: Python: Support multi-config generators for stubgen 2026-09-17 11:27:23 -04:00
William SkellengerandKyle Schwarz 8801e949da CI: Enable interruptible 2026-09-15 17:37:51 -04:00
Samuel BejkoandKyle Schwarz d95a17b360 LIN: Add wakeup request 2026-09-14 17:13:23 -04:00
Kurt WachowskiandKyle Schwarz 3a6501d116 Device: Add ISO-15765 hardware acceleration 2026-09-10 20:52:01 -04:00
Bryant JonesandKyle Schwarz 34875129ee Gigastar: Add FLEXRAY_01 network 2026-09-10 14:18:24 -04:00
Jonathan SchwartzandKyle Schwarz 236c6ad089 Device: Add manufacturing config message 2026-09-10 12:56:55 -04:00
Max Brombach cf58f819cb Platform: Darwin: Replace deprecate kIOMasterPortDefault with kIOMainPortDefault 2026-08-27 18:33:01 +00:00
Kyle Schwarz 07e4eca14a Heartbeat: Include DeviceStatus 2026-08-17 15:34:16 -04:00
Max BrombachandKyle Schwarz 936566170f Communication: Add GenericAPIDataMessage and GenericAPIStatusMessage types 2026-08-17 10:30:35 -04:00
77 changed files with 2990 additions and 175 deletions
+5
View File
@@ -1,3 +1,6 @@
default:
interruptible: true
variables:
DEBIAN_FRONTEND: noninteractive
LIBICSNEO_ICSPB_REPO: https://gitlab-ci-token:${CI_JOB_TOKEN}@${LIBICSNEO_ICSPB_GIT}
@@ -335,6 +338,7 @@ build python/windows:
deploy python/pypi:
stage: deploy
interruptible: false
variables:
TWINE_USERNAME: __token__
TWINE_PASSWORD: $PYPI_TOKEN
@@ -359,6 +363,7 @@ deploy python/pypi:
push github:
stage: deploy
interruptible: false
tags:
- linux-build
image: alpine:latest
+9
View File
@@ -234,8 +234,14 @@ set(SRC_FILES
communication/message/ethernetstatusmessage.cpp
communication/message/networkmutexmessage.cpp
communication/message/clientidmessage.cpp
communication/message/mfgconfigmessage.cpp
communication/message/transmitmessage.cpp
communication/message/spiportkeymessage.cpp
communication/message/genericapidatamessage.cpp
communication/message/genericapistatusmessage.cpp
communication/message/iso15765message.cpp
communication/packet/flexraypacket.cpp
communication/packet/canpacket.cpp
communication/packet/a2bpacket.cpp
@@ -564,9 +570,12 @@ if(LIBICSNEO_BUILD_UNIT_TESTS)
test/unit/a2bencoderdecodertest.cpp
test/unit/mdioencoderdecodertest.cpp
test/unit/livedataencoderdecodertest.cpp
test/unit/macsectest.cpp
test/unit/ringbuffertest.cpp
test/unit/apperrordecodertest.cpp
test/unit/icsneoc2.cpp
test/unit/ethphyregistertest.cpp
test/unit/tc10test.cpp
test/unit/windowsstrings.cpp
test/unit/periodictest.cpp
)
+1 -1
View File
@@ -30,13 +30,13 @@ Instructions for installing each API can be found in its respective documentatio
- neoVI PLASMA
- neoVI RED 2
- RAD-A2B
- RAD-Argos
- RAD-Comet 2
- RAD-Comet 3
- RAD-Epsilon
- RAD-EpsilonXL
- RAD-Galaxy
- RAD-Galaxy 2
- RAD-Gemini
- RAD-Gigastar
- RAD-Gigastar 2
- RAD-Moon 2
+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.BusRecovered) *status_flags |= ICSNEOC2_LIN_STATUS_BUS_RECOVERED;
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;
}
+3
View File
@@ -117,6 +117,7 @@ static constexpr const char* GPTP_NOT_SUPPORTED = "GPTP clock synchronization is
static constexpr const char* SETTING_NOT_AVAILABLE = "Requested a setting that is not available on this device";
static constexpr const char* DISK_FORMAT_NOT_SUPPORTED = "Disk formatting is not supported on this device.";
static constexpr const char* DISK_FORMAT_INVALID_COUNT = "Disk format config disk count is mismatched with device disk count.";
static constexpr const char* TC10_REQUEST_FAILED = "The device rejected the TC10 request.";
// Transport Errors
static constexpr const char* FAILED_TO_READ = "A read operation failed.";
@@ -381,6 +382,8 @@ const char* APIEvent::DescriptionForType(Type type) {
return DISK_FORMAT_NOT_SUPPORTED;
case Type::DiskFormatInvalidCount:
return DISK_FORMAT_INVALID_COUNT;
case Type::TC10RequestFailed:
return TC10_REQUEST_FAILED;
// VSA
case Type::VSABufferCorrupted:
+1 -2
View File
@@ -65,7 +65,6 @@ void EventManager::add(APIEvent event) {
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;
@@ -75,8 +74,8 @@ void EventManager::add(APIEvent event) {
std::lock_guard<std::mutex> eventsLock(eventsMutex);
addEventInternal(event);
} // free the lock so that callbacks may modify events
runCallbacks(event);
}
runCallbacks(event);
}
void EventManager::addEventInternal(APIEvent event) {
+9 -2
View File
@@ -20,9 +20,16 @@ Heartbeat::~Heartbeat() {
void Heartbeat::run() {
EventManager::GetInstance().downgradeErrorsOnCurrentThread();
auto filter = std::make_shared<MessageFilter>(Message::Type::ResetStatus);
auto filter = std::make_shared<MessageFilter>();
filter->includeInternalInAny = true;
bool status = false;
auto cbHandle = device.com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message>) {
auto cbHandle = device.com->addMessageCallback(std::make_shared<MessageCallback>(filter, [&](std::shared_ptr<Message> msg) {
// TODO: remove DeviceStatus after 2027-08-17, as ResetStatus should be widely supported
const bool isHeartbeat =
(msg->type == Message::Type::ResetStatus) ||
(msg->type == Message::Type::RawMessage && std::static_pointer_cast<RawMessage>(msg)->network == Network::NetID::DeviceStatus);
if(!isHeartbeat)
return;
{
std::lock_guard lk(mutex);
status = true;
+19 -23
View File
@@ -545,15 +545,13 @@ int LegacyDLLExport icsneoGetTimeStampForMsg(void* hObject, icsSpyMessage* pMsg,
void LegacyDLLExport icsneoGetISO15765Status(void* hObject, int lNetwork, int lClearTxStatus, int lClearRxStatus,
int* lTxStatus, int* lRxStatus)
{
// TODO Implement
return;
// Not supported
}
void LegacyDLLExport icsneoSetISO15765RxParameters(void* hObject, int lNetwork, int lEnable, spyFilterLong* pFF_CFMsgFilter,
icsSpyMessage* pTxMsg, int lCFTimeOutMs, int lFlowCBlockSize, int lUsesExtendedAddressing, int lUseHardwareIfPresent)
{
// TODO Implement
return;
// Not supported
}
int LegacyDLLExport icsneoGetRTC(void* hObject, icsSpyTime* time)
@@ -835,26 +833,25 @@ int LegacyDLLExport icsneoGetErrorInfo(int lErrorNumber, char* szErrorDescriptio
//ISO15765-2 Functions
int LegacyDLLExport icsneoISO15765_EnableNetworks(void* hObject, unsigned long ulNetworks)
{
// TODO Implement
// Not supported
return false;
}
int LegacyDLLExport icsneoISO15765_DisableNetworks(void* hObject)
{
// TODO Implement
// Not supported
return false;
}
int LegacyDLLExport icsneoISO15765_TransmitMessage(void* hObject, unsigned long ulNetworkID, stCM_ISO157652_TxMessage* pMsg,
unsigned long ulBlockingTimeout)
int LegacyDLLExport icsneoISO15765_TransmitMessage(void* hObject, unsigned long ulNetworkID, stCM_ISO157652_TxMessage* pMsg, unsigned long ulBlockingTimeout)
{
// TODO Implement
// Not supported
return false;
}
int LegacyDLLExport icsneoISO15765_ReceiveMessage(void* hObject, int ulNetworkID, stCM_ISO157652_RxMessage* pMsg)
{
// TODO Implement
// Not supported
return false;
}
@@ -1076,8 +1073,8 @@ int LegacyDLLExport icsneoGetDeviceSettingsType(void* hObject, EPlasmaIonVnetCha
case NEODEVICE_RADMOON3:
*pDeviceSettingsType = DeviceRADMoon3SettingsType;
break;
case NEODEVICE_RADGEMINI:
*pDeviceSettingsType = DeviceRADGeminiSettingsType;
case NEODEVICE_RADARGOS:
*pDeviceSettingsType = DeviceRADArgosSettingsType;
break;
case NEODEVICE_RED2:
*pDeviceSettingsType = DeviceRed2SettingsType;
@@ -1285,10 +1282,11 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
return false;
neodevice_t* device = reinterpret_cast<neodevice_t*>(hObject);
const auto& cmd = static_cast<icsneo::J2534Command>(*CmdBuf);
switch (*CmdBuf)
switch (cmd)
{
case J2534NVCMD_SetNetworkBaudRate:
case icsneo::J2534Command::SetNetworkBaudRate:
pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp;
@@ -1298,7 +1296,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
iRetVal = 0;
break;
case J2534NVCMD_GetNetworkBaudRate:
case icsneo::J2534Command::GetNetworkBaudRate:
{
pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp;
@@ -1311,7 +1309,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
*pTmp = static_cast<uint64_t>(ret);
break;
}
case J2534NVCMD_SetCANFDRate:
case icsneo::J2534Command::SetCANFDRate:
pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp;
@@ -1322,7 +1320,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
iRetVal = 0;
break;
case J2534NVCMD_GetCANFDRate:
case icsneo::J2534Command::GetCANFDRate:
pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp;
@@ -1332,7 +1330,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
*pTmp = icsneo_getFDBaudrate(device, NetworkID);
break;
case J2534NVCMD_GetCANFDTermination:
case icsneo::J2534Command::GetCANFDTermination:
pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp;
@@ -1368,7 +1366,7 @@ int LegacyDLLExport icsneoJ2534Cmd(void* hObject, unsigned char* CmdBuf, short L
}
break;
case J2534NVCMD_SetCANFDTermination:
case icsneo::J2534Command::SetCANFDTermination:
pTmp = (uint64_t *)&CmdBuf[1];
NetworkID = (uint16_t)*pTmp;
@@ -1422,11 +1420,9 @@ int LegacyDLLExport icsneoEnableBusVoltageMonitor(void* hObject, unsigned int en
return false;
}
int LegacyDLLExport icsneoISO15765_TransmitMessageEx(void* hObject,
unsigned long ulNetworkID,
ISO15765_2015_TxMessage* pMsg,
unsigned long ulBlockingTimeout)
int LegacyDLLExport icsneoISO15765_TransmitMessageEx(void* hObject, unsigned long ulNetworkID, ISO15765_2015_TxMessage* pMsg, unsigned long ulBlockingTimeout)
{
// Not supported
return false;
}
+11 -1
View File
@@ -40,6 +40,9 @@ pybind11_add_module(icsneopy
icsneopy/communication/message/livedatamessage.cpp
icsneopy/communication/message/callback/messagecallback.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/flexray/flexray.cpp
icsneopy/disk/diskdriver.cpp
@@ -57,7 +60,14 @@ install(TARGETS icsneopy LIBRARY DESTINATION icsneopy)
find_program(STUBGEN_EXE stubgen)
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)
endif()
+1
View File
@@ -92,6 +92,7 @@ void init_event(pybind11::module_& m) {
.value("SettingNotAvaiableDevice", APIEvent::Type::SettingNotAvaiableDevice)
.value("DiskFormatNotSupported", APIEvent::Type::DiskFormatNotSupported)
.value("DiskFormatInvalidCount", APIEvent::Type::DiskFormatInvalidCount)
.value("TC10RequestFailed", APIEvent::Type::TC10RequestFailed)
.value("FailedToRead", APIEvent::Type::FailedToRead)
.value("FailedToWrite", APIEvent::Type::FailedToWrite)
.value("DriverFailedToOpen", APIEvent::Type::DriverFailedToOpen)
@@ -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("HasUpdatedResponderOnce", &LINStatusFlags::HasUpdatedResponderOnce)
.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");
@@ -39,7 +40,8 @@ void init_linmessage(pybind11::module_& m) {
.value("LIN_BREAK_ONLY", LINMessage::Type::LIN_BREAK_ONLY)
.value("LIN_SYNC_ONLY", LINMessage::Type::LIN_SYNC_ONLY)
.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
.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("clear", &MACsecConfig::clear, 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_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>())
+1 -1
View File
@@ -134,7 +134,7 @@ void init_chipid(pybind11::module_& m) {
.value("SFPModule_lan8670_MCHIP", ChipID::SFPModule_lan8670_MCHIP)
.value("RADGigastar2_ZYNQ", ChipID::RADGigastar2_ZYNQ)
.value("SFPModule_ent11100_MCHIP", ChipID::SFPModule_ent11100_MCHIP)
.value("RADGemini_MCHIP", ChipID::RADGemini_MCHIP)
.value("RADArgos_MCHIP", ChipID::RADArgos_MCHIP)
.value("Invalid", ChipID::Invalid)
.finalize();
}
+2 -1
View File
@@ -34,6 +34,7 @@ void init_device(pybind11::module_& m) {
.def("get_serial", &Device::getSerial)
.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_macsec_networks", &Device::getMACsecNetworks)
.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_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("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("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("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>())
@@ -38,7 +38,7 @@ void init_devicetype(pybind11::module_& m) {
.value("RADGalaxy2", DeviceType::Enum::RADGalaxy2)
.value("RADwBMS", DeviceType::Enum::RADwBMS)
.value("RADMoon3", DeviceType::Enum::RADMoon3)
.value("RADGemini", DeviceType::Enum::RADGemini)
.value("RADArgos", DeviceType::Enum::RADArgos)
.value("RADComet2", DeviceType::Enum::RADComet2)
.value("FIRE3_FlexRay", DeviceType::Enum::FIRE3_FlexRay)
.value("FIRE3_T1S_LIN", DeviceType::Enum::FIRE3_T1S_LIN)
+6
View File
@@ -32,7 +32,10 @@ void init_deviceextension(pybind11::module_&);
void init_chipid(pybind11::module_&);
void init_versionreport(pybind11::module_&);
void init_device(pybind11::module_&);
void init_command(pybind11::module_&);
void init_main51message(pybind11::module_&);
void init_messagefilter(pybind11::module_&);
void init_main51messagefilter(pybind11::module_&);
void init_messagecallback(pybind11::module_&);
void init_version(pybind11::module_&);
void init_flexray(pybind11::module_& m);
@@ -69,7 +72,10 @@ PYBIND11_MODULE(icsneopy, m) {
init_scriptstatusmessage(m);
init_spimessage(m);
init_livedatamessage(m);
init_command(m);
init_main51message(m);
init_messagefilter(m);
init_main51messagefilter(m);
init_messagecallback(m);
init_diskdriver(m);
init_diskdetails(m);
+21
View File
@@ -26,7 +26,10 @@
#include "icsneo/communication/message/ethernetstatusmessage.h"
#include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/clientidmessage.h"
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/communication/message/genericapidatamessage.h"
#include "icsneo/communication/message/genericapistatusmessage.h"
#include "icsneo/communication/command.h"
#include "icsneo/device/device.h"
#include "icsneo/communication/packet/canpacket.h"
@@ -41,6 +44,7 @@
#include "icsneo/communication/packet/i2cpacket.h"
#include "icsneo/communication/packet/scriptstatuspacket.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/iso15765message.h"
#include "icsneo/communication/packet/componentversionpacket.h"
#include "icsneo/communication/packet/supportedfeaturespacket.h"
#include "icsneo/communication/packet/mdiopacket.h"
@@ -345,6 +349,12 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
case ExtendedCommand::ExecuteSPIPortKeyOperation:
result = SPIPortKeyMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::ReadGenericAPIData:
result = GenericAPIDataMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::ReadGenericAPIStatus:
result = GenericAPIStatusMessage::DecodeToMessage(packet->data);
return true;
case ExtendedCommand::GetTC10Status:
result = TC10StatusMessage::DecodeToMessage(packet->data);
return true;
@@ -363,6 +373,9 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
);
protoapi::Id protoId = protoapi::getProtoId(responseBody.data(), responseBody.size());
switch(protoId) {
case protoapi::Id::MfgConfig:
result = MfgConfigMessage::DecodeToMessage(responseBody);
return true;
case protoapi::Id::NetworkMutex:
result = NetworkMutexMessage::DecodeToMessage(responseBody);
return true;
@@ -467,6 +480,14 @@ bool Decoder::decode(std::shared_ptr<Message>& result, const std::shared_ptr<Pac
return true;
}
case Command::J2534Command: {
result = J2534CommandMessage::decodeToMessage(packet->data);
if(!result) {
report(APIEvent::Type::PacketDecodingError, APIEvent::Severity::Error);
return false;
}
return true;
}
default:
auto msg = std::make_shared<Main51Message>();
msg->command = Command(packet->data[0]);
@@ -0,0 +1,28 @@
#include "icsneo/communication/message/genericapidatamessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
std::shared_ptr<GenericAPIDataMessage> GenericAPIDataMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ExtendedResponseMessage::ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::ReadGenericAPIData)
return nullptr;
const size_t required = sizeof(ExtendedResponseMessage::ResponseHeader) + sizeof(GenericAPIDataHeader);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<GenericAPIDataMessage>();
const auto* packet = reinterpret_cast<const GenericAPIDataPacket*>(bytestream.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
msg->functionId = packet->header.functionId;
msg->buffer.resize(packet->header.bufferLength);
std::copy(packet->buffer, packet->buffer + packet->header.bufferLength, msg->buffer.data());
return msg;
}
@@ -0,0 +1,29 @@
#include "icsneo/communication/message/genericapistatusmessage.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/command.h"
using namespace icsneo;
std::shared_ptr<GenericAPIStatusMessage> GenericAPIStatusMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
if(bytestream.size() < sizeof(ExtendedResponseMessage::ResponseHeader))
return nullptr;
const auto* hdr = reinterpret_cast<const ExtendedResponseMessage::ResponseHeader*>(bytestream.data());
if(hdr->command != ExtendedCommand::ReadGenericAPIStatus)
return nullptr;
const size_t required = sizeof(ExtendedResponseMessage::ResponseHeader) + sizeof(GenericAPIStatusResponsePacket);
if(bytestream.size() < required)
return nullptr;
auto msg = std::make_shared<GenericAPIStatusMessage>();
const auto* packet = reinterpret_cast<const GenericAPIStatusResponsePacket*>(bytestream.data() + sizeof(ExtendedResponseMessage::ResponseHeader));
msg->functionId = packet->functionId;
msg->finishedProcessing = static_cast<bool>(packet->finishedProcessing);
msg->functionError = packet->functionError;
msg->callbackError = packet->callbackError;
return msg;
}
+337
View File
@@ -0,0 +1,337 @@
#include "icsneo/communication/message/iso15765message.h"
#include <cstring>
using namespace icsneo;
std::shared_ptr<J2534CommandMessage> J2534CommandMessage::decodeToMessage(const std::vector<uint8_t>& data) {
if(data.size() < 2)
return nullptr;
auto msg = std::make_shared<J2534CommandMessage>((J2534Command)data[1]);
if(data.size() > 2)
msg->setArgumentData(std::vector<uint8_t>(data.begin() + 2, data.end()));
return msg;
}
uint16_t J2534CommandMessage::read16LE(size_t o) const {
return (uint16_t)((uint16_t)argumentData[o] | ((uint16_t)argumentData[o + 1] << 8));
}
void J2534CommandMessage::write16LE(size_t o, uint16_t v) {
argumentData[o] = (uint8_t)(v & 0xFF);
argumentData[o + 1] = (uint8_t)((v >> 8) & 0xFF);
}
uint16_t J2534CommandMessage::read16BE(size_t o) const {
return (uint16_t)(((uint16_t)argumentData[o] << 8) | argumentData[o + 1]);
}
void J2534CommandMessage::write16BE(size_t o, uint16_t v) {
argumentData[o] = (uint8_t)((v >> 8) & 0xFF);
argumentData[o + 1] = (uint8_t)(v & 0xFF);
}
void J2534CommandMessage::writeBits16LE(size_t o, unsigned bitPos, unsigned bitCount, uint32_t value) {
const uint16_t mask = (uint16_t)(((1u << bitCount) - 1u) << bitPos);
uint16_t word = read16LE(o);
word = (uint16_t)((word & ~mask) | (((value << bitPos) & mask)));
write16LE(o, word);
}
uint32_t J2534CommandMessage::read32LE(size_t o) const {
return (uint32_t)argumentData[o]
| ((uint32_t)argumentData[o + 1] << 8)
| ((uint32_t)argumentData[o + 2] << 16)
| ((uint32_t)argumentData[o + 3] << 24);
}
void J2534CommandMessage::write32LE(size_t o, uint32_t v) {
argumentData[o] = (uint8_t)(v & 0xFF);
argumentData[o + 1] = (uint8_t)((v >> 8) & 0xFF);
argumentData[o + 2] = (uint8_t)((v >> 16) & 0xFF);
argumentData[o + 3] = (uint8_t)((v >> 24) & 0xFF);
}
uint32_t J2534CommandMessage::read32BE(size_t o) const {
return ((uint32_t)argumentData[o] << 24) | ((uint32_t)argumentData[o + 1] << 16)
| ((uint32_t)argumentData[o + 2] << 8) | (uint32_t)argumentData[o + 3];
}
void J2534CommandMessage::write32BE(size_t o, uint32_t v) {
argumentData[o] = (uint8_t)((v >> 24) & 0xFF);
argumentData[o + 1] = (uint8_t)((v >> 16) & 0xFF);
argumentData[o + 2] = (uint8_t)((v >> 8) & 0xFF);
argumentData[o + 3] = (uint8_t)(v & 0xFF);
}
J2534_RxCanFilter J2534SetupCanRxFilteringMessage::getRxCanFilter() const {
constexpr size_t filterSize = sizeof(J2534_RxCanFilter::fb);
J2534_RxCanFilter filter = {};
if(argumentData.size() >= (10 + filterSize))
{
filter.idx = (argumentData[2] << 8) | argumentData[3];
filter.enabled = (argumentData[4] << 8) | argumentData[5];
filter.filterCount = (argumentData[6] << 8) | argumentData[7];
filter.fb = *((MessageFilterBytes*)(argumentData.data() + 8));
filter.networkId = (argumentData[8 + filterSize] << 8) | argumentData[9 + filterSize];
}
return filter;
}
void J2534SetupCanRxFilteringMessage::setRxCanFilter(const J2534_RxCanFilter& filter) {
argumentData.resize(10 + sizeof(filter.fb));
argumentData[2] = (filter.idx >> 8) & 0xFF;
argumentData[3] = filter.idx & 0xFF;
argumentData[4] = (filter.enabled >> 8) & 0xFF;
argumentData[5] = filter.enabled & 0xFF;
argumentData[6] = (filter.filterCount >> 8) & 0xFF;
argumentData[7] = filter.filterCount & 0xFF;
*((MessageFilterBytes*)(argumentData.data() + 8)) = filter.fb;
argumentData[8 + sizeof(filter.fb)] = (filter.networkId >> 8) & 0xFF;
argumentData[9 + sizeof(filter.fb)] = filter.networkId & 0xFF;
}
J2534SetupIso15765FlowControlMessage::J2534SetupIso15765FlowControlMessage()
: J2534CommandMessage(J2534Command::SetupIso15765RxFilter) {
argumentData.resize(MessageSize);
// Bytes [0..1] were populated by the base constructor. Everything else starts at zero
// (matches the previous behavior which zeroed the flt region and left the rest of the
// caller-supplied struct as-is; typical callers value-initialized their struct too).
for(size_t i = 2; i < MessageSize; ++i)
argumentData[i] = 0;
}
void J2534SetupIso15765FlowControlMessage::rebuildFilterBytes(void) {
// Zero the 28-byte flt region.
for(size_t i = 0; i < FltSize; ++i)
argumentData[FltOffset + i] = 0;
const uint32_t id = read32LE(IdOffset);
const uint32_t idMask = read32LE(IdMaskOffset);
const bool is29Bit = getFlagBit(FlagId29BitEnable);
const bool extAddr = getFlagBit(FlagExtAddressEnable);
const uint8_t extAddrByte = argumentData[ExtAddrOffset];
// CoreMiniMessageFilterBytes has an interleaved layout:
// uiFilterMask0 at flt+0, uiFilterID0 at flt+2
// uiFilterMask1 at flt+4, uiFilterID1 at flt+6
// uiFilterMask2 at flt+8, uiFilterID2 at flt+10
// datalink.uiFilterMask3 at flt+12, datalink.uiFilterID3 at flt+14
//
// CoreMiniMsgBitsCAN bit layout within each 16-bit unit:
// unit0: IDE(bit0), SRR(bit1), SID(bits2-12), NETWORKINDEX(bits13-15)
// unit1: EID(bits0-11), TXMSG(bit12), ...
// unit2: DLC(bits0-3), ..., RTR(bit9), EID2(bits10-15)
const size_t MaskUnit0 = FltOffset + 0;
const size_t MaskUnit1 = FltOffset + 4;
const size_t MaskUnit2 = FltOffset + 8;
const size_t ValueUnit0 = FltOffset + 2;
const size_t ValueUnit1 = FltOffset + 6;
const size_t ValueUnit2 = FltOffset + 10;
// filter arbid: pMask->IDE = 1
writeBits16LE(MaskUnit0, /*bit*/0, /*width*/1, 1);
if(is29Bit) {
// pValue->IDE = 1; pValue->SID = (id >> 18) & 0x7FF
writeBits16LE(ValueUnit0, 0, 1, 1);
writeBits16LE(ValueUnit0, 2, 11, (id >> 18) & 0x7FF);
// pValue->EID = (id >> 6) & 0xFFF
writeBits16LE(ValueUnit1, 0, 12, (id >> 6) & 0xFFF);
// pValue->EID2 = id & 0x3F
writeBits16LE(ValueUnit2, 10, 6, id & 0x3F);
// pMask->SID = (id_mask >> 18) & 0x7FF
writeBits16LE(MaskUnit0, 2, 11, (idMask >> 18) & 0x7FF);
// pMask->EID = (id_mask >> 6) & 0xFFF (overlaps pValue->{IDE,SID} storage)
writeBits16LE(MaskUnit1, 0, 12, (idMask >> 6) & 0xFFF);
// pMask->EID2 = id_mask & 0x3F (overlaps pValue->EID storage)
writeBits16LE(MaskUnit2, 10, 6, idMask & 0x3F);
} else {
// pValue->IDE = 0 (already zero); pValue->SID = id
writeBits16LE(ValueUnit0, 2, 11, id & 0x7FF);
// pMask->SID = id_mask
writeBits16LE(MaskUnit0, 2, 11, idMask & 0x7FF);
}
// Extended-address filter: writes into the datalink.uiFilterID3 / uiFilterMask3 bytes.
// uiFilterMask3 = flt[12..13] = wire[37..38]
// uiFilterID3 = flt[14..15] = wire[39..40]
if(extAddr) {
const size_t kValueBytes = FltOffset + 14; // uiFilterID3
const size_t kMaskBytes = FltOffset + 12; // uiFilterMask3
argumentData[kValueBytes + 0] = extAddrByte;
argumentData[kMaskBytes + 0] = 0xFF;
argumentData[kValueBytes + 1] = 0;
argumentData[kMaskBytes + 1] = 0;
}
}
uint16_t J2534SetupIso15765FlowControlMessage::getIdx(void) const { return read16LE(IdxOffset); }
void J2534SetupIso15765FlowControlMessage::setIdx(uint16_t idx) { write16LE(IdxOffset, idx); }
uint16_t J2534SetupIso15765FlowControlMessage::getCoreMiniId(void) const { return read16LE(CoreMiniOffset); }
void J2534SetupIso15765FlowControlMessage::setCoreMiniId(uint16_t coreMiniId) { write16LE(CoreMiniOffset, coreMiniId); }
uint8_t J2534SetupIso15765FlowControlMessage::getPadding(void) const { return argumentData[PaddingOffset]; }
void J2534SetupIso15765FlowControlMessage::setPadding(uint8_t padding) { argumentData[PaddingOffset] = padding; }
uint32_t J2534SetupIso15765FlowControlMessage::getId(void) const { return read32LE(IdOffset); }
void J2534SetupIso15765FlowControlMessage::setId(uint32_t id) { write32LE(IdOffset, id); rebuildFilterBytes(); }
uint32_t J2534SetupIso15765FlowControlMessage::getIdMask(void) const { return read32LE(IdMaskOffset); }
void J2534SetupIso15765FlowControlMessage::setIdMask(uint32_t idMask) { write32LE(IdMaskOffset, idMask); rebuildFilterBytes(); }
uint32_t J2534SetupIso15765FlowControlMessage::getFcId(void) const { return read32LE(FcIdOffset); }
void J2534SetupIso15765FlowControlMessage::setFcId(uint32_t fcId) { write32LE(FcIdOffset, fcId); }
uint8_t J2534SetupIso15765FlowControlMessage::getFlowControlExtendedAddress(void) const { return argumentData[FcExtAddrOffset]; }
void J2534SetupIso15765FlowControlMessage::setFlowControlExtendedAddress(uint8_t addr) { argumentData[FcExtAddrOffset] = addr; }
uint8_t J2534SetupIso15765FlowControlMessage::getExtendedAddress(void) const { return argumentData[ExtAddrOffset]; }
void J2534SetupIso15765FlowControlMessage::setExtendedAddress(uint8_t addr) { argumentData[ExtAddrOffset] = addr; rebuildFilterBytes(); }
uint8_t J2534SetupIso15765FlowControlMessage::getBlockSize(void) const { return argumentData[BlockSizeOffset]; }
void J2534SetupIso15765FlowControlMessage::setBlockSize(uint8_t blockSize) { argumentData[BlockSizeOffset] = blockSize; }
uint8_t J2534SetupIso15765FlowControlMessage::getStMin(void) const { return argumentData[StMinOffset]; }
void J2534SetupIso15765FlowControlMessage::setStMin(uint8_t stMin) { argumentData[StMinOffset] = stMin; }
uint16_t J2534SetupIso15765FlowControlMessage::getCfTimeout(void) const { return read16LE(CfTimeoutOffset); }
void J2534SetupIso15765FlowControlMessage::setCfTimeout(uint16_t cfTimeout) { write16LE(CfTimeoutOffset, cfTimeout); }
uint32_t J2534SetupIso15765FlowControlMessage::getFlags(void) const { return read32LE(FlagsOffset); }
void J2534SetupIso15765FlowControlMessage::setFlags(uint32_t flags) { write32LE(FlagsOffset, flags); rebuildFilterBytes(); }
bool J2534SetupIso15765FlowControlMessage::getEnable(void) const { return getFlagBit(FlagEnable); }
void J2534SetupIso15765FlowControlMessage::setEnable(bool enable) { setFlagBit(FlagEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getIs29BitEnabled(void) const { return getFlagBit(FlagId29BitEnable); }
void J2534SetupIso15765FlowControlMessage::setIs29BitEnabled(bool enable) { setFlagBit(FlagId29BitEnable, enable); rebuildFilterBytes(); }
bool J2534SetupIso15765FlowControlMessage::getIsFc29BitEnabled(void) const { return getFlagBit(FlagFcId29BitEnable); }
void J2534SetupIso15765FlowControlMessage::setIsFc29BitEnabled(bool enable) { setFlagBit(FlagFcId29BitEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getExtAddressEnabled(void) const { return getFlagBit(FlagExtAddressEnable); }
void J2534SetupIso15765FlowControlMessage::setExtAddressEnabled(bool enable) { setFlagBit(FlagExtAddressEnable, enable); rebuildFilterBytes(); }
bool J2534SetupIso15765FlowControlMessage::getFcExtAddressEnabled(void) const { return getFlagBit(FlagFcExtAddressEnable); }
void J2534SetupIso15765FlowControlMessage::setFcExtAddressEnabled(bool enable) { setFlagBit(FlagFcExtAddressEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getFlowControlTransmissionEnabled(void) const { return getFlagBit(FlagEnableFlowControlTransmit); }
void J2534SetupIso15765FlowControlMessage::setFlowControlTransmissionEnabled(bool enable) { setFlagBit(FlagEnableFlowControlTransmit, enable); }
bool J2534SetupIso15765FlowControlMessage::getPaddingEnabled(void) const { return getFlagBit(FlagPaddingEnable); }
void J2534SetupIso15765FlowControlMessage::setPaddingEnabled(bool enable) { setFlagBit(FlagPaddingEnable, enable); }
bool J2534SetupIso15765FlowControlMessage::getIsCanFd(void) const { return getFlagBit(FlagIsCanFd); }
void J2534SetupIso15765FlowControlMessage::setIsCanFd(bool enable) { setFlagBit(FlagIsCanFd, enable); }
bool J2534SetupIso15765FlowControlMessage::getIsBrsEnabled(void) const { return getFlagBit(FlagIsBrsEnabled); }
void J2534SetupIso15765FlowControlMessage::setIsBrsEnabled(bool enable) { setFlagBit(FlagIsBrsEnabled, enable); }
void J2534SetupIso15765FlowControlMessage::setFlagBit(uint32_t mask, bool enable) {
uint32_t f = read32LE(FlagsOffset);
if(enable) f |= mask;
else f &= ~mask;
write32LE(FlagsOffset, f);
}
bool J2534SetupIso15765FlowControlMessage::getFlagBit(uint32_t mask) const {
return (read32LE(FlagsOffset) & mask) != 0;
}
uint16_t Iso15765TxSetupMessage::getIdx(void) const { return read16LE(SetupIdxOffset); }
void Iso15765TxSetupMessage::setIdx(uint16_t idx) { write16LE(SetupIdxOffset, idx); }
uint16_t Iso15765TxSetupMessage::getCoreMiniId(void) const { return read16LE(SetupCoreMiniOffset); }
void Iso15765TxSetupMessage::setCoreMiniId(uint16_t coreMiniId) { write16LE(SetupCoreMiniOffset, coreMiniId); }
uint32_t Iso15765TxSetupMessage::getMessageLength(void) const { return read32LE(SetupMsgLenOffset); }
void Iso15765TxSetupMessage::setMessageLength(uint32_t messageLength) { write32LE(SetupMsgLenOffset, messageLength); }
uint8_t Iso15765TxSetupMessage::getPadding(void) const { return argumentData[SetupPaddingOffset]; }
void Iso15765TxSetupMessage::setPadding(uint8_t padding) { argumentData[SetupPaddingOffset] = padding; }
uint8_t Iso15765TxSetupMessage::getTxDl(void) const { return argumentData[SetupTxDlOffset]; }
void Iso15765TxSetupMessage::setTxDl(uint8_t txDl) { argumentData[SetupTxDlOffset] = txDl; }
uint32_t Iso15765TxSetupMessage::getId(void) const { return read32LE(SetupIdOffset); }
void Iso15765TxSetupMessage::setId(uint32_t id) { write32LE(SetupIdOffset, id); }
uint32_t Iso15765TxSetupMessage::getFcId(void) const { return read32LE(SetupFcIdOffset); }
void Iso15765TxSetupMessage::setFcId(uint32_t fcId) { write32LE(SetupFcIdOffset, fcId); }
uint32_t Iso15765TxSetupMessage::getFcIdMask(void) const { return read32LE(SetupFcIdMaskOffset); }
void Iso15765TxSetupMessage::setFcIdMask(uint32_t fcIdMask) { write32LE(SetupFcIdMaskOffset, fcIdMask); }
uint8_t Iso15765TxSetupMessage::getFlowControlExtendedAddress(void) const { return argumentData[SetupFcExtAddrOffset]; }
void Iso15765TxSetupMessage::setFlowControlExtendedAddress(uint8_t addr) { argumentData[SetupFcExtAddrOffset] = addr; }
uint8_t Iso15765TxSetupMessage::getExtendedAddress(void) const { return argumentData[SetupExtAddrOffset]; }
void Iso15765TxSetupMessage::setExtendedAddress(uint8_t addr) { argumentData[SetupExtAddrOffset] = addr; }
uint16_t Iso15765TxSetupMessage::getFsTimeout(void) const { return read16LE(SetupFsTimeoutOffset); }
void Iso15765TxSetupMessage::setFsTimeout(uint16_t timeout) { write16LE(SetupFsTimeoutOffset, timeout); }
uint16_t Iso15765TxSetupMessage::getFsWait(void) const { return read16LE(SetupFsWaitOffset); }
void Iso15765TxSetupMessage::setFsWait(uint16_t wait) { write16LE(SetupFsWaitOffset, wait); }
uint32_t Iso15765TxSetupMessage::getFlags(void) const { return read32LE(SetupFlagsOffset); }
void Iso15765TxSetupMessage::setFlags(uint32_t flags) { write32LE(SetupFlagsOffset, flags); }
uint8_t Iso15765TxSetupMessage::getStMin(void) const { return argumentData[SetupStMinOffset]; }
void Iso15765TxSetupMessage::setStMin(uint8_t stMin) { argumentData[SetupStMinOffset] = stMin; }
uint8_t Iso15765TxSetupMessage::getBlockSize(void) const { return argumentData[SetupBlockSizeOffset]; }
void Iso15765TxSetupMessage::setBlockSize(uint8_t blockSize) { argumentData[SetupBlockSizeOffset] = blockSize; }
bool Iso15765TxSetupMessage::getIs29BitEnabled(void) const { return getFlagBit(FlagId29BitEnable); }
void Iso15765TxSetupMessage::setIs29BitEnabled(bool enable) { setFlagBit(FlagId29BitEnable, enable); }
bool Iso15765TxSetupMessage::getIsFc29BitEnabled(void) const { return getFlagBit(FlagFcId29BitEnable); }
void Iso15765TxSetupMessage::setIsFc29BitEnabled(bool enable) { setFlagBit(FlagFcId29BitEnable, enable); }
bool Iso15765TxSetupMessage::getExtAddressEnabled(void) const { return getFlagBit(FlagExtAddressEnable); }
void Iso15765TxSetupMessage::setExtAddressEnabled(bool enable) { setFlagBit(FlagExtAddressEnable, enable); }
bool Iso15765TxSetupMessage::getFcExtAddressEnabled(void) const { return getFlagBit(FlagFcExtAddressEnable); }
void Iso15765TxSetupMessage::setFcExtAddressEnabled(bool enable) { setFlagBit(FlagFcExtAddressEnable, enable); }
bool Iso15765TxSetupMessage::getOverrideStMin(void) const { return getFlagBit(FlagOverrideStMin); }
void Iso15765TxSetupMessage::setOverrideStMin(bool enable) { setFlagBit(FlagOverrideStMin, enable); }
bool Iso15765TxSetupMessage::getOverrideBlockSize(void) const { return getFlagBit(FlagOverrideBlockSize); }
void Iso15765TxSetupMessage::setOverrideBlockSize(bool enable) { setFlagBit(FlagOverrideBlockSize, enable); }
bool Iso15765TxSetupMessage::getPaddingEnabled(void) const { return getFlagBit(FlagPaddingEnable); }
void Iso15765TxSetupMessage::setPaddingEnabled(bool enable) { setFlagBit(FlagPaddingEnable, enable); }
bool Iso15765TxSetupMessage::getIsCanFd(void) const { return getFlagBit(FlagIsCanFd); }
void Iso15765TxSetupMessage::setIsCanFd(bool enable) { setFlagBit(FlagIsCanFd, enable); }
bool Iso15765TxSetupMessage::getIsBrsEnabled(void) const { return getFlagBit(FlagIsBrsEnabled); }
void Iso15765TxSetupMessage::setIsBrsEnabled(bool enable) { setFlagBit(FlagIsBrsEnabled, enable); }
bool Iso15765TxSetupMessage::getFlagBit(uint32_t mask) const {
return (getFlags() & mask) != 0;
}
void Iso15765TxSetupMessage::setFlagBit(uint32_t mask, bool enable) {
uint32_t f = getFlags();
if(enable) f |= mask;
else f &= ~mask;
setFlags(f);
}
uint16_t Iso15765TxDataMessage::getIdx(void) const { return read16LE(DataIdxOffset); }
void Iso15765TxDataMessage::setIdx(uint16_t idx) { write16LE(DataIdxOffset, idx); }
uint32_t Iso15765TxDataMessage::getOffset(void) const { return read32LE(DataOffsetOffset); }
void Iso15765TxDataMessage::setOffset(uint32_t offset) { write32LE(DataOffsetOffset, offset); }
uint16_t Iso15765TxDataMessage::getLen(void) const { return read16LE(DataLenOffset); }
const uint8_t* Iso15765TxDataMessage::getData(void) const { return argumentData.data() + DataPayloadOffset; }
void Iso15765TxDataMessage::setData(const uint8_t* sourceData, uint16_t len) {
len = std::min(len, (uint16_t)MaxDataLength);
argumentData.resize(DataPayloadOffset + len);
write16LE(DataLenOffset, len);
if(len > 0 && sourceData != nullptr)
std::copy(sourceData, sourceData + len, argumentData.begin() + DataPayloadOffset);
}
@@ -0,0 +1,77 @@
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/icspb.h"
#include <algorithm>
using namespace icsneo;
static MfgConfigMessage::VersionNumber versionFromProto(const settings::common::v1::VersionNumber& version) {
MfgConfigMessage::VersionNumber decoded;
decoded.major = version.major();
decoded.minor = version.minor();
if(version.has_release())
decoded.release = version.release();
if(version.has_build())
decoded.build = version.build();
return decoded;
}
std::shared_ptr<MfgConfigMessage> MfgConfigMessage::DecodeToMessage(const std::vector<uint8_t>& bytestream) {
MfgConfigMessage decoded;
settings::manufacturing::v1::MfgConfig msg;
if(!protoapi::processResponse(bytestream.data(), bytestream.size(), msg)) {
return nullptr;
}
if(msg.has_serial_number()) {
decoded.serialNumber = msg.serial_number();
}
if(msg.has_manufacture_date()) {
const auto& date = msg.manufacture_date();
decoded.manufactureDate = MfgDate{date.manufacture_day(), date.manufacture_month(), date.manufacture_year()};
}
if(msg.has_hardware_rev()) {
decoded.hardwareRev = versionFromProto(msg.hardware_rev());
}
if(msg.has_product_id()) {
decoded.productId = static_cast<uint8_t>(msg.product_id());
}
if(msg.has_bootloader_rev()) {
decoded.bootloaderRev = versionFromProto(msg.bootloader_rev());
}
if(msg.has_usb_descriptor()) {
decoded.usbDescriptor = msg.usb_descriptor();
}
for(const auto& mac : msg.mac_addresses()) {
const auto& bytes = mac.mac_addr();
if(bytes.size() < MACAddressLength)
continue;
MACAddress address{};
std::copy_n(bytes.begin(), MACAddressLength, address.begin());
decoded.macAddresses.push_back(address);
}
if(msg.has_pcb_serial()) {
decoded.pcbSerial = msg.pcb_serial().pcb_serial();
}
if(msg.has_chip_id()) {
decoded.chipId = static_cast<ChipID>(msg.chip_id());
}
if(msg.has_imei()) {
decoded.imei = msg.imei();
}
if(msg.has_parent_product_id()) {
decoded.parentProductId = static_cast<uint8_t>(msg.parent_product_id());
}
if(msg.has_software_version_lock()) {
decoded.softwareVersionLock = versionFromProto(msg.software_version_lock());
}
return std::make_shared<MfgConfigMessage>(decoded);
}
std::vector<uint8_t> MfgConfigMessage::EncodeArgumentsForGet() {
settings::manufacturing::v1::MfgConfig msg;
msg.Clear();
return protoapi::getPayload(protoapi::Command::GET, msg);
}
@@ -137,6 +137,7 @@ static std::vector<uint8_t> EncodeFromMessageLIN(std::shared_ptr<Frame> frame, c
linpacket->CoreMiniBitsLIN.TXResponder = 1;
break;
case LINMessage::Type::LIN_BREAK_ONLY:
linpacket->CoreMiniBitsLIN.TXCommander = 1;
linpacket->CoreMiniBitsLIN.BreakOnly = 1;
break;
default:
+25 -3
View File
@@ -20,7 +20,7 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
if(
(PhyPacketVersion == pHeader->version) &&
(sizeof(PhyRegisterPacket_t) == pHeader->entryBytes) &&
(numEntries <= MaxPhyEntries) &&
(numEntries > 0 && numEntries <= MaxPhyEntries) &&
((bytestream.size() - sizeof(PhyRegisterHeader_t))
== (sizeof(PhyRegisterPacket_t) * numEntries))
)
@@ -30,11 +30,16 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
for(size_t entryIdx{0}; entryIdx < numEntries; ++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>();
phyMessage->Enabled = (pEntry->Enabled != 0u);
phyMessage->WriteEnable = (pEntry->WriteEnable != 0u);
phyMessage->Clause45Enable = (pEntry->Clause45Enable != 0u);
phyMessage->BusIndex = static_cast<uint8_t>(pEntry->BusIndex);
phyMessage->Status = static_cast<uint8_t>(pEntry->status);
phyMessage->Version = static_cast<uint8_t>(pEntry->version);
if(phyMessage->Clause45Enable)
phyMessage->Clause45 = pEntry->clause45;
@@ -43,6 +48,10 @@ std::shared_ptr<EthPhyMessage> HardwareEthernetPhyRegisterPacket::DecodeToMessag
msg->messages.push_back(phyMessage);
}
}
else {
report(APIEvent::Type::ParameterOutOfRange, APIEvent::Severity::Error);
return nullptr;
}
return msg;
}
@@ -59,7 +68,20 @@ bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& m
report(APIEvent::Type::MessageMaxLengthExceeded, APIEvent::Severity::Error);
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.push_back(static_cast<uint8_t>(messageCount & 0xFF));
bytestream.push_back(static_cast<uint8_t>((messageCount >> 8) & 0xFF));
@@ -67,7 +89,7 @@ bool HardwareEthernetPhyRegisterPacket::EncodeFromMessage(const EthPhyMessage& m
bytestream.push_back(static_cast<uint8_t>(sizeof(PhyRegisterPacket_t)));
for(auto& phyMessage : message.messages)
{
PhyRegisterPacket_t tempPacket;
PhyRegisterPacket_t tempPacket{};
tempPacket.Enabled = phyMessage->Enabled ? 0x1u : 0x0u;
tempPacket.WriteEnable = phyMessage->WriteEnable ? 0x1u : 0x0u;
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.HasUpdatedResponderOnce),
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;
else if(msg->statusFlags.BreakOnly)
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.ErrRxBreakTooShort || msg->errFlags.ErrRxSyncNot55 ||
msg->errFlags.ErrRxDataLenOver8 || msg->errFlags.ErrFrameSync ||
msg->errFlags.ErrFrameMessageID || msg->errFlags.ErrChecksumMatch ||
msg->errFlags.ErrFrameResponderData )
msg->errFlags.ErrFrameResponderData) )
{ msg->linMsgType = LINMessage::Type::LIN_ERROR; }
msg->timestamp = packet->timestamp;
@@ -103,7 +115,7 @@ bool HardwareLINPacket::EncodeFromMessage(LINMessage& message, std::vector<uint8
}
case LINMessage::Type::LIN_BREAK_ONLY:
{
size |= 0x20u;
size |= 0x80u | 0x20u;
break;
}
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::RADEpsilon:
case icsneo::DeviceType::Enum::RADGigastar2:
case icsneo::DeviceType::Enum::RADComet2:
case icsneo::DeviceType::Enum::RADComet3:
maxSecY = 2;
maxRule = 2;
maxSa = 4;
binIndex = 0;
break;
default:
maxSecY = 0;
maxSa = 0;
maxRule = 0;
binIndex = 0;
ReportEvent(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return;
}
@@ -515,10 +515,6 @@ MACsecConfig::operator bool() const {
return (maxSa != 0) || (maxSecY != 0) || (maxRule != 0);
}
uint16_t MACsecConfig::getBinIndex() const {
return binIndex;
}
DeviceType MACsecConfig::getType() const {
return type;
}
+319 -7
View File
@@ -8,6 +8,7 @@
#include "icsneo/disk/fat.h"
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
#include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/message/transmitmessage.h"
#ifdef _MSC_VER
@@ -923,6 +924,36 @@ std::shared_ptr<HardwareInfo> Device::getHardwareInfo(std::chrono::milliseconds
return hardwareInfo;
}
std::shared_ptr<MfgConfigMessage> Device::getMfgConfig() {
if(!isOpen()) {
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
return nullptr;
}
std::vector<uint8_t> payload = MfgConfigMessage::EncodeArgumentsForGet();
auto response = com->waitForMessageSync(
[this, payload]() {
return com->sendCommand(ExtendedCommand::ProtobufAPI, payload);
},
std::make_shared<MessageFilter>(Message::Type::MfgConfig),
std::chrono::milliseconds(250)
);
if(!response) {
report(APIEvent::Type::Timeout, APIEvent::Severity::Error);
return nullptr;
}
auto mfgConfig = std::dynamic_pointer_cast<MfgConfigMessage>(response);
if(!mfgConfig) {
report(APIEvent::Type::UnexpectedResponse, APIEvent::Severity::Error);
return nullptr;
}
return mfgConfig;
}
std::optional<uint64_t> Device::readLogicalDisk(uint64_t pos, uint8_t* into, uint64_t amount, std::chrono::milliseconds timeout, Disk::MemoryType memType) {
if(!into || timeout <= std::chrono::milliseconds(0)) {
@@ -2022,7 +2053,12 @@ std::optional<EthPhyMessage> Device::sendEthPhyMsg(const EthPhyMessage& message,
}
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(
[this, bytes](){ return com->sendCommand(Command::PHYControlRegisters, bytes); },
std::make_shared<MessageFilter>(Message::Type::EthernetPhyRegister), timeout);
@@ -3623,7 +3659,7 @@ bool Device::requestTC10Wake(Network::NetID network) {
*(Network::NetID*)args.data() = network;
auto msg = com->waitForMessageSync([&] {
return com->sendCommand(ExtendedCommand::RequestTC10Wake, args);
}, std::make_shared<MessageFilter>(Message::Type::ExtendedResponse), std::chrono::milliseconds(1000));
}, std::make_shared<ExtendedResponseFilter>(ExtendedCommand::RequestTC10Wake), std::chrono::milliseconds(1000));
if(!msg) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
@@ -3636,7 +3672,11 @@ bool Device::requestTC10Wake(Network::NetID network) {
return false;
}
return resp->response == ExtendedResponse::OK;
if(resp->response != ExtendedResponse::OK) {
report(APIEvent::Type::TC10RequestFailed, APIEvent::Severity::Error);
return false;
}
return true;
}
bool Device::requestTC10Sleep(Network::NetID network) {
@@ -3648,7 +3688,7 @@ bool Device::requestTC10Sleep(Network::NetID network) {
*(Network::NetID*)args.data() = network;
auto msg = com->waitForMessageSync([&] {
return com->sendCommand(ExtendedCommand::RequestTC10Sleep, args);
}, std::make_shared<MessageFilter>(Message::Type::ExtendedResponse), std::chrono::milliseconds(1000));
}, std::make_shared<ExtendedResponseFilter>(ExtendedCommand::RequestTC10Sleep), std::chrono::milliseconds(1000));
if(!msg) {
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
@@ -3661,7 +3701,11 @@ bool Device::requestTC10Sleep(Network::NetID network) {
return false;
}
return typed->response == ExtendedResponse::OK;
if(typed->response != ExtendedResponse::OK) {
report(APIEvent::Type::TC10RequestFailed, APIEvent::Severity::Error);
return false;
}
return true;
}
bool Device::reboot(bool safe) {
@@ -3730,7 +3774,15 @@ std::optional<GPTPStatus> Device::getGPTPStatus(std::chrono::milliseconds timeou
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) {
report(APIEvent::Type::MACsecNotSupported, APIEvent::Severity::Error);
return false;
@@ -3741,8 +3793,15 @@ bool Device::writeMACsecConfig(const MACsecConfig& cfg) {
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();
return writeBinaryFile(raw, cfg.getBinIndex());
return writeBinaryFile(raw, binaryIndex->second);
}
bool Device::enableNetworkCommunication(bool enable, uint32_t timeout) {
@@ -4096,3 +4155,256 @@ void Device::restartHeartbeat() {
stopHeartbeat();
startHeartbeat();
}
bool Device::iso15765Enable(const Network& network) {
return J2534_EnableIso15765(network, true);
}
bool Device::iso15765DisableAll(void) {
bool ok = true;
for(const auto& slot : iso15765FirmwareEnabled)
{
if (slot.second)
{
if (!J2534_EnableIso15765(slot.first, false))
ok = false;
}
}
return ok;
}
bool Device::iso15765TransmitMessage(const Network& network, const Iso15765MessageArgs& msg, const std::chrono::milliseconds& timeout) {
if (!isOnline())
return false;
if(iso15765FirmwareEnabled.find(network) == iso15765FirmwareEnabled.end() || !iso15765FirmwareEnabled[network])
return false;
bool result;
Iso15765TxSetupMessage setupMsg;
//Set the network ID to use
if(const auto& coreMiniId = network.getCoreMini())
setupMsg.setCoreMiniId((uint16_t)*coreMiniId);
const uint8_t txIndex = msg.getTxIndex();
setupMsg.setIdx(txIndex);
setupMsg.setId(msg.getArbId().Id);
setupMsg.setFcId(msg.getFlowControlArbId().Id);
setupMsg.setFcIdMask(msg.getFlowControlArbIdMask());
setupMsg.setFsTimeout(msg.getFsTimeout());
setupMsg.setFsWait(msg.getFsWaitTimeout());
const uint32_t messageLength = (uint32_t)msg.getData().size();
setupMsg.setMessageLength(messageLength);
setupMsg.setIs29BitEnabled(msg.getArbId().Is29Bit);
setupMsg.setIsFc29BitEnabled(msg.getFlowControlArbId().Is29Bit);
if(const auto& extAddress = msg.getExtendedAddress())
{
setupMsg.setExtAddressEnabled(true);
setupMsg.setExtendedAddress(*extAddress);
}
if(const auto& extFcAddress = msg.getFlowControlExtendedAddress())
{
setupMsg.setFcExtAddressEnabled(true);
setupMsg.setFlowControlExtendedAddress(*extFcAddress);
}
if(const auto& stMin = msg.getStMin())
{
setupMsg.setOverrideStMin(true);
setupMsg.setStMin(*stMin);
}
if(const auto& blockSize = msg.getBlockSize())
{
setupMsg.setOverrideBlockSize(true);
setupMsg.setBlockSize(*blockSize);
}
if(const auto& padding = msg.getPaddingValue())
{
setupMsg.setPaddingEnabled(true);
setupMsg.setPadding(*padding);
}
setupMsg.setIsBrsEnabled(msg.getIsBrsEnabled());
setupMsg.setIsCanFd(msg.getIsCanFd());
setupMsg.setTxDl(msg.getTxDl());
{
uint32_t octetsToSend = messageLength;
const uint8_t* payload = msg.getData().data();
uint32_t offset = 0;
result = J2534_Transaction(network, std::move(setupMsg), timeout);
while(result && octetsToSend)
{
const uint16_t chunkSize = (uint16_t)std::min((uint32_t)Iso15765TxDataMessage::MaxDataLength, octetsToSend);
Iso15765TxDataMessage dataMsg;
dataMsg.setIdx(txIndex);
dataMsg.setOffset(offset);
dataMsg.setData(&payload[offset], chunkSize);
result = J2534_Transaction(network, std::move(dataMsg), timeout);
offset += chunkSize;
octetsToSend -= chunkSize;
}
}
return result;
}
bool Device::iso15765SetupRxFlowControl(const Network& network, const Iso15765MessageArgs& msg) {
if (!isOnline())
return false;
if(iso15765FirmwareEnabled.find(network) == iso15765FirmwareEnabled.end() || !iso15765FirmwareEnabled[network])
return false;
J2534SetupIso15765FlowControlMessage rxFlowControl;
rxFlowControl.setIsBrsEnabled(msg.getIsBrsEnabled());
rxFlowControl.setIsCanFd(msg.getIsCanFd());
rxFlowControl.setIdx(msg.getTxIndex());
if(const auto& coreMiniId = network.getCoreMini())
rxFlowControl.setCoreMiniId((uint16_t)*coreMiniId);
rxFlowControl.setEnable(true);
if(const auto& blockSize = msg.getBlockSize())
{
rxFlowControl.setBlockSize(*blockSize);
}
rxFlowControl.setCfTimeout(msg.getCfTimeout());
rxFlowControl.setFlowControlTransmissionEnabled(msg.getIsFlowControlEnabled());
if(const auto& extAddress = msg.getExtendedAddress())
{
rxFlowControl.setExtendedAddress(*extAddress);
rxFlowControl.setExtAddressEnabled(true);
}
if(const auto& fcExtAddress = msg.getFlowControlExtendedAddress())
{
rxFlowControl.setFlowControlExtendedAddress(*fcExtAddress);
rxFlowControl.setFcExtAddressEnabled(true);
}
rxFlowControl.setFcId(msg.getFlowControlArbId().Id);
rxFlowControl.setIsFc29BitEnabled(msg.getFlowControlArbId().Is29Bit);
rxFlowControl.setIs29BitEnabled(msg.getArbId().Is29Bit);
rxFlowControl.setId(msg.getArbId().Id);
rxFlowControl.setIdMask(msg.getFlowControlArbIdMask());
if(const auto& padding = msg.getPaddingValue())
{
rxFlowControl.setPadding(*padding);
rxFlowControl.setPaddingEnabled(true);
}
if(const auto& stMin = msg.getStMin())
{
rxFlowControl.setStMin(*stMin);
}
return J2534_Transaction(network, std::move(rxFlowControl), std::chrono::milliseconds(0));
}
bool Device::J2534_Transaction(const Network& network, J2534CommandMessage&& msg, const std::chrono::milliseconds& timeout) {
msg.network = network;
if (timeout.count())
{
static std::shared_ptr<MessageFilter> filter = std::make_shared<Main51MessageFilter>(Command::J2534Command);
const auto& response = com->waitForMessageSync([&](void)
{
return com->sendCommand(msg.command, msg.getArgumentData());
}, filter, timeout);
if (!response)
{
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
return false;
}
auto responseMsg = std::dynamic_pointer_cast<Main51Message>(response);
if (!responseMsg || responseMsg->command != Command::J2534Command)
{
report(APIEvent::Type::MessageFormattingError, APIEvent::Severity::Error);
return false;
}
}
else
{
return com->sendCommand(msg.command, msg.getArgumentData());
}
// NOTE: responseMsg->data.front()
return true;
}
bool Device::J2534_ClearRxFilters(const Network& network)
{
return J2534_Transaction(network, J2534CommandMessage(J2534CommandMessage::J2534Command::SetupClearCanRxFilters, { (uint8_t)0 /* is this necessary? */}), std::chrono::milliseconds(0));
}
bool Device::J2534_SetupCanRxFilter(const Network& network, const J2534_RxCanFilter& rxCanFilter)
{
return J2534_Transaction(network, J2534SetupCanRxFilteringMessage(rxCanFilter), std::chrono::milliseconds(0));
}
bool Device::J2534_EnableFiltering(const Network& network, const bool enable)
{
return J2534_Transaction(network, J2534EnableFilteringMessage(enable), std::chrono::milliseconds(0));
}
bool Device::J2534_EnableIso15765(const Network& network, const bool enable)
{
if (iso15765FirmwareEnabled[network] == enable)
return true;
if (!J2534_Transaction(network, J2534EnableMessage(enable), std::chrono::milliseconds(0)))
return false;
iso15765FirmwareEnabled[network] = enable;
if (enable)
{
// Turn OFF filtering of CAN messages in the firmware
return J2534_EnableFirmwareUsbPassFilters(network, false);
}
return true;
}
bool Device::J2534_ClearRxFilter(const Network& network, unsigned int iIndex)
{
if (const auto& slot = iso15765FirmwareEnabled.find(network); slot != iso15765FirmwareEnabled.end() && slot->second)
{
J2534_RxCanFilter rxFilter;
memset(&rxFilter, 0, sizeof(rxFilter));
rxFilter.idx = (uint16_t)iIndex;
return J2534_SetupCanRxFilter(network, rxFilter);
}
return false;
}
bool Device::J2534_EnableFirmwareUsbPassFilters(const Network& network, const bool enable)
{
const auto& slot = iso15765FirmwareEnabled.find(network);
if (slot == iso15765FirmwareEnabled.end())
return false;
//check for disconnect here!
if (!slot->second)
{
// Tried to shut-off Rx table message filtering but FW ISO15765 was not enabled
return true; //just ignore it, no filtering can occur anyway
}
if (enable) //turning ON filtering in the Firmware based on the rx table
{
//Rx table message filtering is on by default in the firmware when m_bISO15765_FW_Enabled is true
//need to check here to see if we set index 0 to a PASS all filter (i.e. turned off USB filtering)
if (!J2534_ClearRxFilters(network))
return false;
}
// New "filtering enable" mechanism - old firmware ignores this frame
return J2534_EnableFiltering(network, enable);
}
+4 -4
View File
@@ -221,8 +221,8 @@ std::vector<std::shared_ptr<Device>> DeviceFinder::FindAll() {
makeIfSerialMatches<RADMoon3>(dev, newFoundDevices);
#endif
#ifdef __RADGEMINI_H_
makeIfSerialMatches<RADGemini>(dev, newFoundDevices);
#ifdef __RADARGOS_H_
makeIfSerialMatches<RADArgos>(dev, newFoundDevices);
#endif
#ifdef __RADMOONDUO_H_
@@ -388,8 +388,8 @@ const std::vector<DeviceType>& DeviceFinder::GetSupportedDevices() {
RADMoon3::DEVICE_TYPE,
#endif
#ifdef __RADGEMINI_H_
RADGemini::DEVICE_TYPE,
#ifdef __RADARGOS_H_
RADArgos::DEVICE_TYPE,
#endif
#ifdef __RADMOONDUO_H_
+5
View File
@@ -36,6 +36,7 @@ option(LIBICSNEO_BUILD_CPP_ANALOG_OUT_EXAMPLE "Build the analog output example."
option(LIBICSNEO_BUILD_CPP_DISKFORMAT_EXAMPLE "Build the disk format example." ON)
option(LIBICSNEO_BUILD_CPP_T1S_EXAMPLE "Build the T1S example." ON)
option(LIBICSNEO_BUILD_CPP_GPTP_EXAMPLE "Build the C++ gPTP settings example." ON)
option(LIBICSNEO_BUILD_CPP_ISO15765_LOOPBACK_EXAMPLE "Build the C++ ISO15765 two-device CAN1 loopback example." ON)
add_compile_options(${LIBICSNEO_COMPILER_WARNINGS})
@@ -190,3 +191,7 @@ endif()
if(LIBICSNEO_BUILD_CPP_GPTP_EXAMPLE)
add_subdirectory(cpp/gptp)
endif()
if(LIBICSNEO_BUILD_CPP_ISO15765_LOOPBACK_EXAMPLE)
add_subdirectory(cpp/iso15765_loopback)
endif()
@@ -0,0 +1,2 @@
add_executable(libicsneocpp-iso15765-loopback src/ISO15765Loopback.cpp)
target_link_libraries(libicsneocpp-iso15765-loopback icsneocpp)
@@ -0,0 +1,450 @@
#include <cctype>
#include <chrono>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>
#include "icsneo/icsneocpp.h"
namespace {
using namespace std::chrono_literals;
enum class Mode {
None,
Raw,
SingleFrame,
Both,
};
struct Options {
Mode mode = Mode::None;
std::string testerSerial;
std::string ecuSerial;
int64_t baud = 500000;
bool keepBaud = false;
uint32_t txId = 0x7E0;
uint32_t fcId = 0x7E8;
std::optional<size_t> payloadBytes;
int listenMs = 2000;
uint8_t padding = 0x00;
uint16_t fsTimeoutMs = 75;
uint16_t fsWaitMs = 150;
uint16_t cfTimeoutMs = 150;
};
std::mutex gLogMutex;
void logLine(const std::string& line) {
std::lock_guard<std::mutex> lk(gLogMutex);
std::cout << line << std::endl;
}
bool iequals(const std::string& a, const std::string& b) {
if(a.size() != b.size())
return false;
for(size_t i = 0; i < a.size(); i++) {
if(std::tolower(static_cast<unsigned char>(a[i])) != std::tolower(static_cast<unsigned char>(b[i])))
return false;
}
return true;
}
std::string hexBytes(const std::vector<uint8_t>& data) {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for(size_t i = 0; i < data.size(); i++) {
if(i)
oss << ' ';
oss << std::setw(2) << static_cast<unsigned>(data[i]);
}
return oss.str();
}
std::string pciDescribe(const std::vector<uint8_t>& data) {
if(data.empty())
return {};
const uint8_t pciType = static_cast<uint8_t>(data[0] >> 4);
const uint8_t pciLow = static_cast<uint8_t>(data[0] & 0x0F);
std::ostringstream oss;
switch(pciType) {
case 0x0:
if(pciLow > 7 || data.size() < static_cast<size_t>(1 + pciLow))
return {};
oss << "SF len=" << static_cast<unsigned>(pciLow);
break;
case 0x1: {
if(data.size() < 8)
return {};
const uint16_t len = static_cast<uint16_t>((pciLow << 8) | data[1]);
if(len < 8)
return {};
oss << "FF len=" << len;
break;
}
case 0x2:
if(data.size() < 2)
return {};
oss << "CF SN=" << static_cast<unsigned>(pciLow);
break;
case 0x3: {
if(data.size() < 3 || pciLow > 2)
return {};
static const char* fsName[] = { "CTS", "WAIT", "OVFLW" };
oss << "FC FS=" << fsName[pciLow];
oss << " BS=" << static_cast<unsigned>(data[1]);
oss << " STmin=0x" << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<unsigned>(data[2]);
break;
}
default:
return {};
}
return oss.str();
}
void printUsage(const char* argv0) {
std::cerr
<< "Usage: " << argv0 << " --raw|--sf|--both [options]\n\n"
<< "Two Intrepid devices with CAN1 wired together (CANH/CANL, terminated).\n"
<< "Prints CAN1 frames with ISO-TP PCI decode (SF/FF/CF/FC).\n\n"
<< "Modes:\n"
<< " --raw Raw CAN ping-pong (cable check)\n"
<< " --sf Firmware ISO-TP single-frame TX from tester\n"
<< " --both Firmware ISO-TP TX on tester, firmware flow-control on ECU\n\n"
<< "Devices:\n"
<< " --tester SERIAL Tester (sender) serial\n"
<< " --ecu SERIAL ECU / peer serial\n"
<< " Optional if exactly two devices are found.\n\n"
<< "Optional:\n"
<< " --baud N CAN1 baud (default 500000, applied temporarily)\n"
<< " --keep-baud Do not change device baud\n"
<< " --tx-id HEX Tester ISO-TP CAN ID (default 0x7E0)\n"
<< " --fc-id HEX Flow-control CAN ID (default 0x7E8)\n"
<< " --bytes N ISO-TP payload size (sf default 5, both default 20)\n"
<< " --listen-ms N Time to listen after the action (default 2000)\n";
}
uint32_t parseU32(const std::string& s) {
return static_cast<uint32_t>(std::stoul(s, nullptr, 0));
}
bool parseArgs(int argc, char** argv, Options& opt) {
for(int i = 1; i < argc; i++) {
const std::string a = argv[i];
auto need = [&](const char* name) -> std::string {
if(i + 1 >= argc)
throw std::runtime_error(std::string("missing value for ") + name);
return argv[++i];
};
if(a == "--raw")
opt.mode = Mode::Raw;
else if(a == "--sf")
opt.mode = Mode::SingleFrame;
else if(a == "--both")
opt.mode = Mode::Both;
else if(a == "--tester")
opt.testerSerial = need("--tester");
else if(a == "--ecu")
opt.ecuSerial = need("--ecu");
else if(a == "--baud")
opt.baud = static_cast<int64_t>(std::stoll(need("--baud")));
else if(a == "--keep-baud")
opt.keepBaud = true;
else if(a == "--tx-id")
opt.txId = parseU32(need("--tx-id"));
else if(a == "--fc-id")
opt.fcId = parseU32(need("--fc-id"));
else if(a == "--bytes")
opt.payloadBytes = static_cast<size_t>(std::stoul(need("--bytes")));
else if(a == "--listen-ms")
opt.listenMs = std::stoi(need("--listen-ms"));
else if(a == "-h" || a == "--help") {
printUsage(argv[0]);
return false;
} else {
std::cerr << "Unknown argument: " << a << "\n";
printUsage(argv[0]);
return false;
}
}
if(opt.mode == Mode::None) {
printUsage(argv[0]);
return false;
}
return true;
}
size_t defaultPayloadSize(Mode mode) {
return mode == Mode::SingleFrame ? 5 : 20;
}
std::vector<uint8_t> makePayload(size_t n) {
std::vector<uint8_t> data(n);
for(size_t i = 0; i < n; i++)
data[i] = static_cast<uint8_t>(i & 0xFF);
return data;
}
bool isExtended(uint32_t id) {
return id > 0x7FFu;
}
void printApiResult(const char* what, bool ok) {
std::ostringstream oss;
oss << " " << what << ": " << (ok ? "OK" : "FAIL");
if(!ok) {
const auto err = icsneo::GetLastError();
if(err.getType() != icsneo::APIEvent::Type::NoErrorFound)
oss << " [" << err << "]";
}
logLine(oss.str());
}
bool transmitCan(icsneo::Device& device, uint32_t arbId, std::vector<uint8_t> data) {
auto frame = std::make_shared<icsneo::CANMessage>();
frame->network = icsneo::Network::NetID::DWCAN_01;
frame->arbid = arbId;
frame->data = std::move(data);
frame->isExtended = isExtended(arbId);
frame->isCANFD = false;
const bool ok = device.transmit(frame);
if(!ok)
printApiResult("transmit CAN", ok);
return ok;
}
void fillIso15765(icsneo::Iso15765MessageArgs& msg, const Options& opt, const std::vector<uint8_t>& payload, bool rx) {
msg.setTxIndex(0);
msg.setArbId(icsneo::Iso15765MessageArgs::ArbId(opt.txId, isExtended(opt.txId)));
msg.setFlowControlArbId(icsneo::Iso15765MessageArgs::ArbId(opt.fcId, isExtended(opt.fcId)));
msg.setFlowControlArbIdMask(isExtended(opt.txId) ? 0x1FFFFFFFu : 0x7FFu);
msg.setIsCanFd(false);
msg.setIsBrsEnabled(false);
msg.setTxDl(8);
msg.setPaddingValue(opt.padding);
msg.setFsTimeout(opt.fsTimeoutMs);
msg.setFsWaitTimeout(opt.fsWaitMs);
msg.setCfTimeout(opt.cfTimeoutMs);
msg.setIsFlowControlEnabled(rx);
if(!payload.empty()) {
auto copy = payload;
msg.setData(std::move(copy));
}
}
struct Sniffer {
const char* tag = "";
std::optional<uint64_t> t0;
std::mutex t0Mutex;
void onCan(const std::shared_ptr<icsneo::CANMessage>& can) {
{
std::lock_guard<std::mutex> lk(t0Mutex);
if(!t0)
t0 = can->timestamp;
}
double relMs = 0.0;
{
std::lock_guard<std::mutex> lk(t0Mutex);
if(t0 && can->timestamp >= *t0)
relMs = static_cast<double>(can->timestamp - *t0) / 1e6;
}
std::ostringstream oss;
oss << " [" << tag << (can->transmitted ? " TX" : " RX") << "] "
<< std::fixed << std::setprecision(3) << relMs << " ms "
<< can->network << " 0x" << std::hex << std::uppercase
<< std::setw(isExtended(can->arbid) ? 8 : 3) << std::setfill('0') << can->arbid
<< std::dec << " [" << can->data.size() << "] " << hexBytes(can->data);
const auto pci = pciDescribe(can->data);
if(!pci.empty())
oss << " " << pci;
logLine(oss.str());
}
};
void addCanSniffer(icsneo::Device& device, Sniffer& sniffer) {
auto filter = std::make_shared<icsneo::MessageFilter>(icsneo::Network::NetID::DWCAN_01);
device.addMessageCallback(std::make_shared<icsneo::MessageCallback>(filter, [&sniffer](std::shared_ptr<icsneo::Message> message) {
if(message->type != icsneo::Message::Type::Frame)
return;
auto frame = std::static_pointer_cast<icsneo::Frame>(message);
if(frame->network.getType() != icsneo::Network::Type::CAN)
return;
sniffer.onCan(std::static_pointer_cast<icsneo::CANMessage>(message));
}));
}
bool openAndOnline(std::shared_ptr<icsneo::Device>& device, const Options& opt) {
logLine(std::string("Opening ") + device->describe() + " ...");
if(!device->open()) {
printApiResult("open", false);
return false;
}
if(!opt.keepBaud && device->settings) {
if(!device->settings->setBaudrateFor(icsneo::Network::NetID::DWCAN_01, opt.baud))
printApiResult("setBaudrateFor", false);
else if(!device->settings->apply(true))
printApiResult("settings->apply(temporary)", false);
}
if(!device->goOnline()) {
printApiResult("goOnline", false);
device->close();
return false;
}
return true;
}
void closeDevice(const std::shared_ptr<icsneo::Device>& device) {
if(!device)
return;
device->iso15765DisableAll();
if(device->isOnline())
device->goOffline();
if(device->isOpen())
device->close();
}
bool enableIso(icsneo::Device& device, const char* who) {
const bool ok = device.iso15765Enable(icsneo::Network(icsneo::Network::NetID::DWCAN_01));
printApiResult((std::string(who) + " ISO15765_Enable").c_str(), ok);
return ok;
}
bool receiveIso(icsneo::Device& device, const Options& opt) {
icsneo::Iso15765MessageArgs msg;
fillIso15765(msg, opt, {}, true);
const bool ok = device.iso15765SetupRxFlowControl(icsneo::Network(icsneo::Network::NetID::DWCAN_01), msg);
printApiResult("ECU ISO15765_ReceiveMessage", ok);
return ok;
}
bool transmitIso(icsneo::Device& device, const Options& opt, const std::vector<uint8_t>& payload) {
icsneo::Iso15765MessageArgs msg;
fillIso15765(msg, opt, payload, false);
const bool ok = device.iso15765TransmitMessage(
icsneo::Network(icsneo::Network::NetID::DWCAN_01), msg, std::chrono::milliseconds(0));
printApiResult("tester ISO15765_TransmitMessage", ok);
return ok;
}
std::shared_ptr<icsneo::Device> findBySerial(const std::vector<std::shared_ptr<icsneo::Device>>& devices, const std::string& serial) {
for(const auto& d : devices) {
if(iequals(d->getSerial(), serial))
return d;
}
return nullptr;
}
} // namespace
int main(int argc, char** argv) {
Options opt;
try {
if(!parseArgs(argc, argv, opt))
return 1;
} catch(const std::exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
}
std::cout << "libicsneo " << icsneo::GetVersion() << std::endl;
auto devices = icsneo::FindAllDevices();
std::cout << "Found " << devices.size() << " device(s)\n";
for(const auto& d : devices)
std::cout << " " << d->describe() << " serial=" << d->getSerial() << "\n";
if(devices.size() < 2) {
std::cerr << "Need two devices connected.\n";
return 1;
}
std::shared_ptr<icsneo::Device> tester;
std::shared_ptr<icsneo::Device> ecu;
if(opt.testerSerial.empty() && opt.ecuSerial.empty()) {
if(devices.size() != 2) {
std::cerr << "More than two devices found; pass --tester and --ecu serials.\n";
return 1;
}
tester = devices[0];
ecu = devices[1];
std::cout << "No serials given; using first as tester, second as ECU.\n";
} else {
if(opt.testerSerial.empty() || opt.ecuSerial.empty()) {
std::cerr << "Pass both --tester and --ecu, or neither.\n";
return 1;
}
tester = findBySerial(devices, opt.testerSerial);
ecu = findBySerial(devices, opt.ecuSerial);
if(!tester || !ecu) {
std::cerr << "Could not match tester/ECU serials.\n";
return 1;
}
}
const size_t payloadSize = opt.payloadBytes.value_or(defaultPayloadSize(opt.mode));
const auto payload = makePayload(payloadSize);
std::cout << "Tester: " << tester->describe() << "\n"
<< "ECU: " << ecu->describe() << "\n";
if(opt.mode != Mode::Raw) {
std::ostringstream hdr;
hdr << "CAN1 TX 0x" << std::hex << std::uppercase << opt.txId
<< " FC 0x" << opt.fcId << std::dec
<< " payload " << payloadSize << " bytes";
std::cout << hdr.str() << "\n";
}
std::cout << std::endl;
if(!openAndOnline(tester, opt) || !openAndOnline(ecu, opt))
return 1;
Sniffer testerSniff;
testerSniff.tag = "TESTER";
Sniffer ecuSniff;
ecuSniff.tag = "ECU ";
addCanSniffer(*tester, testerSniff);
addCanSniffer(*ecu, ecuSniff);
switch(opt.mode) {
case Mode::Raw:
logLine("Mode --raw: tester 0x123, then ECU 0x456");
transmitCan(*tester, 0x123, { 0x11, 0x22, 0x33, 0x44 });
std::this_thread::sleep_for(200ms);
transmitCan(*ecu, 0x456, { 0x55, 0x66, 0x77, 0x88 });
break;
case Mode::SingleFrame:
logLine("Mode --sf: firmware ISO-TP single frame from tester");
if(payload.size() > 7)
logLine(" warning: payload > 7 bytes will be a First Frame (no flow control in this mode)");
enableIso(*tester, "tester");
transmitIso(*tester, opt, payload);
break;
case Mode::Both:
logLine("Mode --both: firmware TX on tester, firmware flow-control on ECU");
enableIso(*tester, "tester");
enableIso(*ecu, "ECU");
receiveIso(*ecu, opt);
std::this_thread::sleep_for(100ms);
transmitIso(*tester, opt, payload);
break;
case Mode::None:
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(opt.listenMs));
closeDevice(tester);
closeDevice(ecu);
return 0;
}
+1 -1
View File
@@ -77,7 +77,7 @@ int main(int, char**) {
cfg.setTxEnable(true);
// 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 << icsneo::GetLastError() << std::endl;
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()
+125 -25
View File
@@ -1,33 +1,133 @@
#ifndef _J2534_H
#define _J2534_H
#include <cstdint>
namespace icsneo {
//J2534 Commands
#define J1534_NUM_PERIOD_TX_MSGS 128
#define J1534_NUM_PERIOD_RX_MSGS 128
#define J2534NVCMD_SetISJ2534 0
#define J2534NVCMD_SetISO5Baud 1
#define J2534NVCMD_SetISOFastInit 2
#define J2534NVCMD_SetISOCheckSum 3
#define J2534NVCMD_SetISO9141Parms 4
#define J2534NVCMD_GetISO9141Parms 5
#define J2534NVCMD_ISO9141APIChkSum 6
#define J2534NVCMD_SetNetworkBaudRate 7
#define J2534NVCMD_GetNetworkBaudRate 8
#define J2534NVCMD_EnableTransmitEvent 9
#define J2534NVCMD_SetTransmitEvent 10
#define J2534NVCMD_BlueEnableStopFilters 11
#define J2534NVCMD_Blue15765HWSupport 12
#define J2534NVCMD_GetTXBufferInfo 13
#define J2534NVCMD_GetEncryptionKey 14
#define J2534NVCMD_SetMiscIOForVBATT 15
#define J2534NVCMD_EnableISO_KW_Network 16
#define J2534NVCMD_SetJ1708CheckSum 17
#define J2534NVCMD_GetTimestamp 18
#define J2534NVCMD_GetCANFDRate 19
#define J2534NVCMD_SetCANFDRate 20
#define J2534NVCMD_GetCANFDTermination 21
#define J2534NVCMD_SetCANFDTermination 22
#define J2534NVCMD_GetCANFDFormat 23
#define J2534NVCMD_SetCANFDFormat 24
enum class J2534Command : uint8_t {
SetISJ2534 = 0,
SetISO5Baud = 1,
SetISOFastInit = 2,
SetISOCheckSum = 3,
SetISO9141Parms = 4,
GetISO9141Parms = 5,
ISO9141APIChkSum = 6,
SetNetworkBaudRate = 7,
GetNetworkBaudRate = 8,
EnableTransmitEvent = 9,
SetTransmitEvent = 10,
BlueEnableStopFilters = 11,
Blue15765HWSupport = 12,
GetTXBufferInfo = 13,
GetEncryptionKey = 14,
SetMiscIOForVBATT = 15,
EnableISO_KW_Network = 16,
SetJ1708CheckSum = 17,
GetTimestamp = 18,
GetCANFDRate = 19,
SetCANFDRate = 20,
GetCANFDTermination = 21,
SetCANFDTermination = 22,
GetCANFDFormat = 23,
SetCANFDFormat = 24
};
#pragma pack(push)
#pragma pack(1)
/**
* SubFrame Commands
*/
enum class J2534SubCommand : uint8_t {
Enable = 0,
SetupIso15765RxFilter = 1,
SetupIso15765TxMessageProperties = 2,
SetupIso15765TxMessageDataBytes = 3,
SetupCanRxFilter = 4,
SetupClearCanRxFilters = 5,
EnableFiltering = 6
};
typedef struct
{
uint16_t uiFilterMask0;
uint16_t uiFilterID0;
uint16_t uiFilterMask1;
uint16_t uiFilterID1;
uint16_t uiFilterMask2;
uint16_t uiFilterID2;
union {
/** Mask and value words if rx filter is datalink filter*/
struct
{
uint16_t uiFilterMask3;
uint16_t uiFilterID3;
uint16_t uiFilterMask4;
uint16_t uiFilterID4;
uint16_t uiFilterMask5;
uint16_t uiFilterID5;
uint16_t uiFilterMask6;
uint16_t uiFilterID6;
} datalink;
/** Mask and value bytes if rx filter is datalink filter*/
struct
{
uint8_t uiFilterMask_DB0;
uint8_t uiFilterMask_DB1;
uint8_t uiFilterID_DB0;
uint8_t uiFilterID_DB1;
uint8_t uiFilterMask_DB2;
uint8_t uiFilterMask_DB3;
uint8_t uiFilterID_DB2;
uint8_t uiFilterID_DB3;
uint8_t uiFilterMask_DB4;
uint8_t uiFilterMask_DB5;
uint8_t uiFilterID_DB4;
uint8_t uiFilterID_DB5;
uint8_t uiFilterMask_DB6;
uint8_t uiFilterMask_DB7;
uint8_t uiFilterID_DB6;
uint8_t uiFilterID_DB7;
} datalinkBytes;
/** Mask and value bytes if rx filter is Iso15765-2*/
struct
{
uint8_t uiFilterMask_DB0;
uint8_t uiFilterID_DB0;
uint8_t uiFilterMask_DB1;
uint8_t uiFilterID_DB1;
uint8_t uiFilterMask_DB2;
uint8_t uiFilterID_DB2;
uint8_t uiFilterMask_DB3;
uint8_t uiFilterID_DB3;
uint8_t uiFilterMask_DB4;
uint8_t uiFilterID_DB4;
uint8_t uiFilterMask_DB5;
uint8_t uiFilterID_DB5;
uint8_t uiFilterMask_DB6;
uint8_t uiFilterID_DB6;
uint8_t uiFilterMask_DB7;
uint8_t uiFilterID_DB7;
} iso15Bytes;
} args;
} MessageFilterBytes;
typedef struct
{
uint16_t idx;
uint16_t enabled;
uint16_t filterCount;
MessageFilterBytes fb;
uint16_t networkId;
} J2534_RxCanFilter;
#pragma pack(pop)
} // namespace icsneo
#endif
+1
View File
@@ -126,6 +126,7 @@ public:
SettingNotAvaiableDevice = 0x2057,
DiskFormatNotSupported = 0x2058,
DiskFormatInvalidCount = 0x2059,
TC10RequestFailed = 0x205A,
// Transport Events
FailedToRead = 0x3000,
+4
View File
@@ -43,6 +43,7 @@ enum class Command : uint8_t {
GetLogicalDiskInfo = 0xBB, // Previously known as RED_CMD_GET_SDCARD_INFO
RequestStatusUpdate = 0xBC,
ReadSettings = 0xC7, // Previously known as 3G_READ_SETTINGS_EX
J2534Command = 0xD7, // Previously known as RED_CMD_J2534_EXTENSION
SetVBattMonitor = 0xDB, // Previously known as RED_CMD_CM_VBATT_MONITOR
RequestBitSmash = 0xDC, // Previously known as RED_CMD_CM_BITSMASH
WiVICommand = 0xDD, // Previously known as RED_CMD_WIVI_COMM
@@ -73,8 +74,11 @@ enum class ExtendedCommand : uint16_t {
GetComponentVersions = 0x001A,
SoftwareUpdate = 0x001B,
Reboot = 0x001C,
ReadGenericAPIStatus = 0x001D,
SetRootFSEntryFlags = 0x0027,
TransmitCoreminiMessage = 0x0028,
ReadGenericAPIData = 0x002E,
WriteGenericAPICommand = 0x002F,
GenericBinaryInfo = 0x0030,
LiveData = 0x0035,
ExecuteSPIPortKeyOperation = 0x003C,
+6
View File
@@ -9,6 +9,7 @@
#include <common/v1/proto_header.pb.h>
#include <commands/generic/v1/client_id.pb.h>
#include <commands/network/v1/mutex.pb.h>
#include <settings/manufacturing/v1/mfg_config.pb.h>
#ifdef _WIN32
#pragma warning(pop)
#endif
@@ -36,6 +37,11 @@ struct IDLookup {
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_UNSPECIFIED;
};
template <>
struct IDLookup<settings::manufacturing::v1::MfgConfig> {
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_MFG_CONFIG;
};
template <>
struct IDLookup<commands::network::v1::NetworkMutex> {
constexpr static common::v1::ProtoId value = common::v1::ProtoId::PROTO_ID_NETWORK_MUTEX;
@@ -8,6 +8,7 @@
#include "icsneo/communication/packet.h"
#include <vector>
#include <memory>
#include <optional>
namespace icsneo {
@@ -17,13 +18,16 @@ namespace icsneo {
#endif
struct PhyMessage {
bool Enabled;
bool WriteEnable;
bool Clause45Enable;
uint8_t BusIndex;
uint8_t Version;
bool Enabled = false;
bool WriteEnable = false;
bool Clause45Enable = false;
uint8_t BusIndex = 0;
uint8_t Version = PhyPacketVersion;
// Unset on locally constructed messages; every decoded response sets the raw wire status.
// Ignored when sending. A value does not establish firmware error coverage.
std::optional<uint8_t> Status;
union {
Clause22Message Clause22;
Clause22Message Clause22{};
Clause45Message Clause45;
};
};
@@ -0,0 +1,44 @@
#ifndef __GENERICAPIDATAMESSAGE_H_
#define __GENERICAPIDATAMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include <vector>
#include <memory>
namespace icsneo {
class GenericAPIDataMessage : public Message {
public:
static constexpr size_t GENERIC_API_BUFFER_SIZE = 513;
#pragma pack(push, 1)
struct GenericAPIDataHeader {
uint16_t bufferLength;
uint8_t apiIndex;
uint8_t instance;
uint8_t functionId;
};
struct GenericAPIDataPacket
{
GenericAPIDataHeader header;
uint8_t buffer[GENERIC_API_BUFFER_SIZE];
};
#pragma pack(pop)
static std::shared_ptr<GenericAPIDataMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
GenericAPIDataMessage() : Message(Type::GenericAPIData) {}
uint8_t functionId;
std::vector<uint8_t> buffer;
};
} // namespace icsneo
#endif // __cplusplus
#endif // __GENERICAPIDATAMESSAGE_H_
@@ -0,0 +1,40 @@
#ifndef __GENERICAPISTATUSMESSAGE_H_
#define __GENERICAPISTATUSMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include <memory>
namespace icsneo {
class GenericAPIStatusMessage : public Message {
public:
#pragma pack(push, 2)
struct GenericAPIStatusResponsePacket
{
uint8_t apiIndex;
uint8_t instance;
uint8_t functionId;
uint8_t functionError;
uint8_t callbackError;
uint8_t finishedProcessing;
};
#pragma pack(pop)
static std::shared_ptr<GenericAPIStatusMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
GenericAPIStatusMessage() : Message(Type::GenericAPIStatus) {}
uint8_t functionId;
bool finishedProcessing;
uint8_t functionError;
uint8_t callbackError;
};
} // namespace icsneo
#endif // __cplusplus
#endif // __GENERICAPISTATUSMESSAGE_H_
@@ -0,0 +1,443 @@
#ifndef __ISO_15765MESSAGE_H_
#define __ISO_15765MESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/main51message.h"
#include "icsneo/communication/command.h"
#include "icsneo/J2534.h"
#include <memory>
#include <optional>
#include <vector>
namespace icsneo {
class J2534CommandMessage : public Main51Message
{
public:
enum class J2534Command : uint8_t
{
Enable = 0, //RED_CMD_J2534_EXTENSION_ENABLE,
SetupIso15765RxFilter = 1, //RED_CMD_J2534_EXTENSION_SETUP_ISO15_RX_FILTER,
SetupIso15765TxMessageProperties = 2, //RED_CMD_J2534_EXTENSION_SETUP_ISO15_TX_MESSAGE_PROPERTIES,
SetupIso15765TxMessageDataBytes = 3, //RED_CMD_J2534_EXTENSION_SETUP_ISO15_TX_MESSAGE_DATABYTES,
SetupCanRxFilter = 4, //RED_CMD_J2534_EXTENSION_SETUP_CAN_RX_FILTER,
SetupClearCanRxFilters = 5, //RED_CMD_J2534_EXTENSION_SETUP_CLEAR_CAN_RX_FILTERS,
EnableFiltering = 6, //RED_CMD_J2534_EXTENSION_ENABLE_FILTERING,
};
J2534CommandMessage(const J2534Command j2534Command, const std::vector<uint8_t>& arguments = {})
: Main51Message() {
command = Command::J2534Command;
argumentData.push_back((uint8_t)j2534Command);
argumentData.push_back(0);
setArgumentData(arguments);
}
virtual ~J2534CommandMessage(void) = default;
J2534Command getJ2534Command(void) const { return (J2534Command)argumentData[0]; }
void setJ2534Command(const J2534Command& j2534Command) { argumentData[0] = (uint8_t)j2534Command; }
const std::vector<uint8_t>& getArgumentData(void) const { return argumentData; }
void setArgumentData(const std::vector<uint8_t>& arguments) { argumentData.insert(argumentData.end(), arguments.begin(), arguments.end()); }
static std::shared_ptr<J2534CommandMessage> decodeToMessage(const std::vector<uint8_t>& data);
protected:
std::vector<uint8_t> argumentData;
uint16_t read16LE(size_t o) const;
void write16LE(size_t o, uint16_t v);
uint16_t read16BE(size_t o) const;
void write16BE(size_t o, uint16_t v);
void writeBits16LE(size_t o, unsigned bitPos, unsigned bitCount, uint32_t value);
uint32_t read32LE(size_t o) const;
void write32LE(size_t o, uint32_t v);
uint32_t read32BE(size_t o) const;
void write32BE(size_t o, uint32_t v);
};
class J2534EnableMessage : public J2534CommandMessage {
public:
J2534EnableMessage(const bool enable)
: J2534CommandMessage(J2534Command::Enable, { (uint8_t)enable }) {
}
bool getEnable(void) const { return (bool)argumentData[2]; }
void setEnable(bool enable) { argumentData[2] = (uint8_t)enable; }
};
class J2534EnableFilteringMessage : public J2534CommandMessage {
public:
J2534EnableFilteringMessage(const bool enable)
: J2534CommandMessage(J2534Command::EnableFiltering, { (uint8_t)enable }) {
}
bool getEnable(void) const { return (bool)argumentData[2]; }
void setEnable(bool enable) { argumentData[2] = (uint8_t)enable; }
};
class J2534SetupCanRxFilteringMessage : public J2534CommandMessage {
public:
J2534SetupCanRxFilteringMessage(const J2534_RxCanFilter& filter)
: J2534CommandMessage(J2534Command::SetupCanRxFilter) {
setRxCanFilter(filter);
}
J2534_RxCanFilter getRxCanFilter(void) const;
void setRxCanFilter(const J2534_RxCanFilter& filter);
};
class J2534SetupIso15765FlowControlMessage : public J2534CommandMessage
{
public:
J2534SetupIso15765FlowControlMessage();
uint16_t getIdx(void) const;
void setIdx(uint16_t idx);
uint16_t getCoreMiniId(void) const;
void setCoreMiniId(uint16_t coreMiniId);
uint8_t getPadding(void) const;
void setPadding(uint8_t padding);
uint32_t getId(void) const;
void setId(uint32_t id);
uint32_t getIdMask(void) const;
void setIdMask(uint32_t idMask);
uint32_t getFcId(void) const;
void setFcId(uint32_t fcId);
uint8_t getFlowControlExtendedAddress(void) const;
void setFlowControlExtendedAddress(uint8_t addr);
uint8_t getExtendedAddress(void) const;
void setExtendedAddress(uint8_t addr);
uint8_t getBlockSize(void) const;
void setBlockSize(uint8_t blockSize);
uint8_t getStMin(void) const;
void setStMin(uint8_t stMin);
uint16_t getCfTimeout(void) const;
void setCfTimeout(uint16_t cfTimeout);
uint32_t getFlags(void) const;
void setFlags(uint32_t flags);
bool getEnable(void) const;
void setEnable(bool enable);
bool getIs29BitEnabled(void) const;
void setIs29BitEnabled(bool enable);
bool getIsFc29BitEnabled(void) const;
void setIsFc29BitEnabled(bool enable);
bool getExtAddressEnabled(void) const;
void setExtAddressEnabled(bool enable);
bool getFcExtAddressEnabled(void) const;
void setFcExtAddressEnabled(bool enable);
bool getFlowControlTransmissionEnabled(void) const;
void setFlowControlTransmissionEnabled(bool enable);
bool getPaddingEnabled(void) const;
void setPaddingEnabled(bool enable);
bool getIsCanFd(void) const;
void setIsCanFd(bool enable);
bool getIsBrsEnabled(void) const;
void setIsBrsEnabled(bool enable);
private:
// The legacy wire format was the raw memory of the (now-removed) J2534_RxFlowControlRequest
// struct copied into mArgumentData starting at offset 1 (overwriting the header pad byte).
// The struct was compiled with `#pragma pack(2)` on MSVC little-endian. All multi-byte
// scalars are therefore stored little-endian; the "flt" region reproduces the exact
// byte pattern produced by the old MessageBitsCAN bitfield writes.
//
// Byte layout (mArgumentData indices):
// [0] J2534 command header byte (set by base class)
// [1] padding
// [2..3] idx (u16 LE)
// [4..5] iCoreMiniID (u16 LE)
// [6] padding (u8)
// [7] structure pad byte (unused)
// [8..11] id (u32 LE)
// [12..15] id_mask (u32 LE)
// [16..19] fc_id (u32 LE)
// [20] flowControlExtendedAddress (u8)
// [21] extendedAddress (u8)
// [22] blockSize (u8)
// [23] stMin (u8)
// [24..25] cf_timeout (u16 LE)
// [26..53] MessageFilterBytes flt (28 bytes) -- see RebuildFilterBytes for details
// [54..57] flags (u32 LE) -- see kFcFlag* below
//
// Total wire size: 58 bytes.
static const size_t MessageSize = 58;
static const size_t IdxOffset = 2;
static const size_t CoreMiniOffset = 4;
static const size_t PaddingOffset = 6;
static const size_t IdOffset = 8;
static const size_t IdMaskOffset = 12;
static const size_t FcIdOffset = 16;
static const size_t FcExtAddrOffset = 20;
static const size_t ExtAddrOffset = 21;
static const size_t BlockSizeOffset = 22;
static const size_t StMinOffset = 23;
static const size_t CfTimeoutOffset = 24;
static const size_t FltOffset = 26; // 28 bytes
static const size_t FltSize = 28;
static const size_t FlagsOffset = 54;
// Bit positions inside the u32 LE flags word (matches the legacy bitfield layout).
static const uint32_t FlagEnable = 1u << 0;
static const uint32_t FlagId29BitEnable = 1u << 1;
static const uint32_t FlagFcId29BitEnable = 1u << 2;
static const uint32_t FlagExtAddressEnable = 1u << 3;
static const uint32_t FlagFcExtAddressEnable = 1u << 4;
static const uint32_t FlagEnableFlowControlTransmit = 1u << 5;
static const uint32_t FlagPaddingEnable = 1u << 6;
static const uint32_t FlagIsCanFd = 1u << 7;
static const uint32_t FlagIsBrsEnabled = 1u << 8;
// Rebuilds the filter bytes region of mArgumentData based on the current id / id_mask /
// id_29_bit_enable / ext_address_enable / extendedAddress state. Preserves the legacy
// (pre-existing) wire format bit-for-bit.
void rebuildFilterBytes(void);
void setFlagBit(uint32_t mask, bool enable);
bool getFlagBit(uint32_t mask) const;
};
class Iso15765TxSetupMessage : public J2534CommandMessage {
public:
Iso15765TxSetupMessage()
: J2534CommandMessage(J2534Command::SetupIso15765TxMessageProperties) {
argumentData.resize(36);
}
uint16_t getIdx(void) const;
void setIdx(uint16_t idx);
uint16_t getCoreMiniId(void) const;
void setCoreMiniId(uint16_t coreMiniId);
uint32_t getMessageLength(void) const;
void setMessageLength(uint32_t messageLength);
uint8_t getPadding(void) const;
void setPadding(uint8_t padding);
uint8_t getTxDl(void) const;
void setTxDl(uint8_t txDl);
uint32_t getId(void) const;
void setId(uint32_t id);
uint32_t getFcId(void) const;
void setFcId(uint32_t fcId);
uint32_t getFcIdMask(void) const;
void setFcIdMask(uint32_t fcIdMask);
uint8_t getFlowControlExtendedAddress(void) const;
void setFlowControlExtendedAddress(uint8_t addr);
uint8_t getExtendedAddress(void) const;
void setExtendedAddress(uint8_t addr);
uint16_t getFsTimeout(void) const;
void setFsTimeout(uint16_t timeout);
uint16_t getFsWait(void) const;
void setFsWait(uint16_t wait);
uint32_t getFlags(void) const;
void setFlags(uint32_t flags);
uint8_t getStMin(void) const;
void setStMin(uint8_t stMin);
uint8_t getBlockSize(void) const;
void setBlockSize(uint8_t blockSize);
bool getIs29BitEnabled(void) const;
void setIs29BitEnabled(bool enable);
bool getIsFc29BitEnabled(void) const;
void setIsFc29BitEnabled(bool enable);
bool getExtAddressEnabled(void) const;
void setExtAddressEnabled(bool enable);
bool getFcExtAddressEnabled(void) const;
void setFcExtAddressEnabled(bool enable);
bool getOverrideStMin(void) const;
void setOverrideStMin(bool enable);
bool getOverrideBlockSize(void) const;
void setOverrideBlockSize(bool enable);
bool getPaddingEnabled(void) const;
void setPaddingEnabled(bool enable);
bool getIsCanFd(void) const;
void setIsCanFd(bool enable);
bool getIsBrsEnabled(void) const;
void setIsBrsEnabled(bool enable);
private:
// Matches J2534_Iso15TxRequest (#pragma pack(2), little-endian) copied after the
// 2-byte J2534 command header, as sent by vspy3 J2534_Transaction.
// [0..1] J2534 command header (managed by base class)
// [2..3] idx (u16 LE)
// [4..5] iCoreMiniID (u16 LE)
// [6..9] messageLength (u32 LE)
// [10] padding
// [11] tx_dl
// [12..15] id (u32 LE)
// [16..19] fc_id (u32 LE)
// [20..23] fc_id_mask (u32 LE)
// [24] flowControlExtendedAddress
// [25] extendedAddress
// [26..27] fs_timeout (u16 LE)
// [28..29] fs_wait (u16 LE)
// [30..33] flags (u32 LE)
// [34] stMin
// [35] blockSize
static const size_t SetupIdxOffset = 2;
static const size_t SetupCoreMiniOffset = 4;
static const size_t SetupMsgLenOffset = 6;
static const size_t SetupPaddingOffset = 10;
static const size_t SetupTxDlOffset = 11;
static const size_t SetupIdOffset = 12;
static const size_t SetupFcIdOffset = 16;
static const size_t SetupFcIdMaskOffset = 20;
static const size_t SetupFcExtAddrOffset = 24;
static const size_t SetupExtAddrOffset = 25;
static const size_t SetupFsTimeoutOffset = 26;
static const size_t SetupFsWaitOffset = 28;
static const size_t SetupFlagsOffset = 30;
static const size_t SetupStMinOffset = 34;
static const size_t SetupBlockSizeOffset = 35;
// Flag bit positions within the 32-bit flags word.
static const uint32_t FlagId29BitEnable = 1u << 0;
static const uint32_t FlagFcId29BitEnable = 1u << 1;
static const uint32_t FlagExtAddressEnable = 1u << 2;
static const uint32_t FlagFcExtAddressEnable = 1u << 3;
static const uint32_t FlagOverrideStMin = 1u << 4;
static const uint32_t FlagOverrideBlockSize = 1u << 5;
static const uint32_t FlagPaddingEnable = 1u << 6;
static const uint32_t FlagIsCanFd = 1u << 7;
static const uint32_t FlagIsBrsEnabled = 1u << 8;
bool getFlagBit(uint32_t mask) const;
void setFlagBit(uint32_t mask, bool enable);
};
class Iso15765TxDataMessage : public J2534CommandMessage {
public:
static constexpr uint16_t MaxDataLength = 500;
Iso15765TxDataMessage()
: J2534CommandMessage(J2534Command::SetupIso15765TxMessageDataBytes) {
argumentData.resize(10);
}
uint16_t getIdx(void) const;
void setIdx(uint16_t idx);
uint32_t getOffset(void) const;
void setOffset(uint32_t offset);
uint16_t getLen(void) const;
const uint8_t* getData(void) const;
void setData(const uint8_t* sourceData, uint16_t len);
private:
// Matches J2534_Iso15TxDataRequest (#pragma pack(2), little-endian) after the
// 2-byte J2534 command header.
// [0..1] J2534 command header (managed by base class)
// [2..3] idx (u16 LE)
// [4..7] offset (u32 LE)
// [8..9] len (u16 LE)
// [10..] data
static const size_t DataIdxOffset = 2;
static const size_t DataOffsetOffset = 4;
static const size_t DataLenOffset = 8;
static const size_t DataPayloadOffset = 10;
};
class Iso15765MessageArgs {
public:
struct ArbId {
bool Is29Bit;
uint32_t Id;
ArbId(uint32_t id = 0, bool is29Bit = false)
: Is29Bit(is29Bit)
, Id(id) {
}
};
Iso15765MessageArgs(void)
: networkId(0)
, txIndex(0)
, arbId({ false, 0 })
, flowControlArbId({ false, 0 })
, flowControlArbIdMask(0)
, isCanFd(false)
, isBrsEnabled(false)
, tx_DL(8)
, fs_Timeout(0)
, fs_WaitTimeout(0)
, cf_Timeout(0)
, isFlowControlEnabled(false) {
}
uint16_t getNetworkId(void) const { return networkId; }
void setNetworkId(uint16_t netId) { networkId = netId; }
uint8_t getTxIndex(void) const { return txIndex; }
void setTxIndex(uint8_t idx) { txIndex = idx; }
const ArbId& getArbId(void) const { return arbId; }
void setArbId(const ArbId& id) { arbId = id; }
const ArbId& getFlowControlArbId(void) const { return flowControlArbId; }
void setFlowControlArbId(const ArbId& id) { flowControlArbId = id; }
uint32_t getFlowControlArbIdMask(void) const { return flowControlArbIdMask; }
void setFlowControlArbIdMask(uint32_t mask) { flowControlArbIdMask = mask; }
bool getIsCanFd(void) const { return isCanFd; }
void setIsCanFd(bool value) { isCanFd = value; }
bool getIsBrsEnabled(void) const { return isBrsEnabled; }
void setIsBrsEnabled(bool value) { isBrsEnabled = value; }
uint8_t getTxDl(void) const { return tx_DL; }
void setTxDl(uint8_t txDl) { tx_DL = txDl; }
std::optional<uint8_t> getStMin(void) const { return stMin; }
void setStMin(std::optional<uint8_t> v) { stMin = v; }
std::optional<uint8_t> getBlockSize(void) const { return blockSize; }
void setBlockSize(std::optional<uint8_t> b) { blockSize = b; }
std::optional<uint8_t> getFlowControlExtendedAddress(void) const { return flowControlExtendedAddress; }
void setFlowControlExtendedAddress(std::optional<uint8_t> fcExtAddr) { flowControlExtendedAddress = fcExtAddr; }
std::optional<uint8_t> getExtendedAddress(void) const { return extendedAddress; }
void setExtendedAddress(std::optional<uint8_t> extAddr) { extendedAddress = extAddr; }
std::optional<uint8_t> getPaddingValue(void) const { return paddingValue; }
void setPaddingValue(std::optional<uint8_t> v) { paddingValue = v; }
uint16_t getFsTimeout(void) const { return fs_Timeout; }
void setFsTimeout(uint16_t timeout) { fs_Timeout = timeout; }
uint16_t getFsWaitTimeout(void) const { return fs_WaitTimeout; }
void setFsWaitTimeout(uint16_t timeout) { fs_WaitTimeout = timeout; }
uint16_t getCfTimeout(void) const { return cf_Timeout; }
void setCfTimeout(uint16_t timeout) { cf_Timeout = timeout; }
const std::vector<uint8_t>& getData(void) const { return data; }
void setData(std::vector<uint8_t>&& d) { data = std::move(d); }
bool getIsFlowControlEnabled(void) const { return isFlowControlEnabled; }
void setIsFlowControlEnabled(bool enabled) { isFlowControlEnabled = enabled; }
protected:
uint16_t networkId; // The netid of the message (determines which network to transmit on)
uint8_t txIndex; // identifier for this transmit message
ArbId arbId; // arbId of transmitted frames (CAN id to transmit to)
ArbId flowControlArbId; // flow control arb id filter value (response id from receiver)
uint32_t flowControlArbIdMask; // The flow control arb id filter mask (response id from receiver)
bool isCanFd;
bool isBrsEnabled;
uint8_t tx_DL; // Maximum CAN(FD) protocol length for transmitted frames (Valid values are 8, 12, 16, 20, 24, 32, 48, 64)
std::optional<uint8_t> stMin; // Overrides the stMin that the receiver reports (Set to J2534's STMIN_TX if <= 0xFF)
std::optional<uint8_t> blockSize; // Overrides the block size that the receiver reports (Set to J2534's BS_TX if <= 0xFF)
std::optional<uint8_t> flowControlExtendedAddress; // Expected Extended Address byte of response from receiver
std::optional<uint8_t> extendedAddress; // Extended Address byte of transmitter
std::optional<uint8_t> paddingValue; // The padding byte to use to fill the unused portion of transmitted CAN frames (single frame, first frame, consecutive frame)
uint16_t fs_Timeout; // max timeout (ms) for waiting on flow control response (Set this to N_BS_MAX's value if J2534)
uint16_t fs_WaitTimeout; // max timeout (ms) for waiting on flow control response after receiving flow control with flow status set to WAIT (Set this to N_BS_MAX's value if J2534)
uint16_t cf_Timeout; // max timeout (ms) for waiting on consecutive frame (Set this to N_CR_MAX's value in J2534)
std::vector<uint8_t> data;
bool isFlowControlEnabled; // Enables Flow Control frame transmission (Rx message; from neoVI to ECU)
};
}
#endif // __cplusplus
#endif
@@ -34,6 +34,7 @@ struct LINStatusFlags {
bool HasUpdatedResponderOnce = false;
bool BusRecovered = false;
bool BreakOnly = false;
bool WakeupRequest = false;
};
class LINMessage : public Frame {
@@ -45,7 +46,8 @@ public:
LIN_BREAK_ONLY = icsneoc2_lin_msg_type_break_only,
LIN_SYNC_ONLY = icsneoc2_lin_msg_type_sync_only,
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);
@@ -49,6 +49,9 @@ public:
ClientId = 0x8017,
AllMACAddresses = 0x8018,
SPIPortKeyOperation = 0x8019,
GenericAPIData = 0x8020,
GenericAPIStatus = 0x8021,
MfgConfig = 0x8022,
};
Message(Type t) : type(t) {}
@@ -0,0 +1,56 @@
#ifndef __MFGCONFIGMESSAGE_H_
#define __MFGCONFIGMESSAGE_H_
#ifdef __cplusplus
#include "icsneo/communication/message/message.h"
#include "icsneo/communication/message/allmacaddressesmessage.h"
#include "icsneo/device/chipid.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>
namespace icsneo {
class MfgConfigMessage : public Message {
public:
struct MfgDate {
uint32_t day = 0;
uint32_t month = 0;
uint32_t year = 0;
};
struct VersionNumber {
uint32_t major = 0;
uint32_t minor = 0;
std::optional<uint32_t> release;
std::optional<uint32_t> build;
};
MfgConfigMessage() : Message(Message::Type::MfgConfig) {}
static std::shared_ptr<MfgConfigMessage> DecodeToMessage(const std::vector<uint8_t>& bytestream);
static std::vector<uint8_t> EncodeArgumentsForGet();
std::optional<uint64_t> serialNumber;
std::optional<MfgDate> manufactureDate;
std::optional<VersionNumber> hardwareRev;
std::optional<uint8_t> productId;
std::optional<VersionNumber> bootloaderRev;
std::optional<std::string> usbDescriptor;
std::vector<MACAddress> macAddresses;
std::optional<std::string> pcbSerial;
std::optional<ChipID> chipId;
std::optional<uint64_t> imei;
std::optional<uint8_t> parentProductId;
std::optional<VersionNumber> softwareVersionLock;
};
} // namespace icsneo
#endif // __cplusplus
#endif // __MFGCONFIGMESSAGE_H_
@@ -65,7 +65,7 @@ struct PhyRegisterPacket_t {
#pragma pack(pop)
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 FiveBits = 0x1Fu;
@@ -47,7 +47,8 @@ struct HardwareLINPacket {
uint16_t ResponderByteFerr : 1; //Framing error in one of our responder bytes.
uint16_t TxAborted : 1;//!< This transmit was aborted.
uint16_t BreakOnly : 1;
uint16_t : 2;
uint16_t WakeupRequest : 1; //!< LIN wakeup pulse.
uint16_t : 1;
} CoreMiniBitsLIN;
uint8_t data[8];
-2
View File
@@ -150,7 +150,6 @@ private:
uint8_t maxSecY;
uint8_t maxSa;
uint8_t maxRule;
uint16_t binIndex;
DeviceType type;
std::vector<MACsecRxRule> rxRule;
@@ -205,7 +204,6 @@ public:
void clear();
std::vector<uint8_t> serialize() const;
operator bool() const;
uint16_t getBinIndex() const;
DeviceType getType() const;
uint8_t getMaxNumRule() const;
uint8_t getMaxNumSecY() const;
+3 -2
View File
@@ -91,9 +91,10 @@ struct FlashPhase : public BootloaderPhase {
bool authenticate = true;
bool encrypt = true;
bool checkOutOfDate = true;
uint8_t slot = UINT8_MAX;
FlashPhase(ChipID chip, BootloaderCommunication comm, bool authenticate = true, bool encrypt = true, bool checkOutOfDate = true)
: chip(chip), comm(comm), authenticate(authenticate), encrypt(encrypt), checkOutOfDate(checkOutOfDate) {}
FlashPhase(ChipID chip, BootloaderCommunication comm, bool authenticate = true, bool encrypt = true, bool checkOutOfDate = true, uint8_t slot = UINT8_MAX)
: chip(chip), comm(comm), authenticate(authenticate), encrypt(encrypt), checkOutOfDate(checkOutOfDate), slot(slot) {}
};
enum class BootloaderSetting {
+1 -1
View File
@@ -138,7 +138,7 @@ enum class ChipID : icsneoc2_chip_id_t {
RADMOONT1S_ZCHIP = icsneoc2_chip_id_radmoont1s_zchip,
RADGigastar2_ZYNQ = icsneoc2_chip_id_radgigastar2_zynq,
SFPModule_ent11100_MCHIP = icsneoc2_chip_id_sfpmodule_ent11100_mchip,
RADGemini_MCHIP = icsneoc2_chip_id_radgemini_mchip,
RADArgos_MCHIP = icsneoc2_chip_id_radargos_mchip,
Invalid = icsneoc2_chip_id_invalid
};
+39 -2
View File
@@ -12,6 +12,7 @@
#include <type_traits>
#include <optional>
#include <unordered_map>
#include <map>
#include <set>
#include <unordered_set>
#include <chrono>
@@ -47,6 +48,8 @@
#include "icsneo/communication/message/livedatamessage.h"
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/communication/message/spiportkeymessage.h"
#include "icsneo/communication/message/genericapidatamessage.h"
#include "icsneo/communication/message/genericapistatusmessage.h"
#include "icsneo/core/macseccfg.h"
#include "icsneo/communication/packet/genericbinarystatuspacket.h"
#include "icsneo/communication/packet/livedatapacket.h"
@@ -61,6 +64,9 @@
#include "icsneo/communication/message/gptpstatusmessage.h"
#include "icsneo/communication/message/networkmutexmessage.h"
#include "icsneo/communication/message/allmacaddressesmessage.h"
#include "icsneo/communication/message/mfgconfigmessage.h"
#include "icsneo/communication/message/iso15765message.h"
#include "icsneo/J2534.h"
#define ICSNEO_FINDABLE_DEVICE_BASE(className, type) \
static constexpr DeviceType::Enum DEVICE_TYPE = type; \
@@ -145,7 +151,7 @@ public:
RADMoonT1S = 56,
RADGigastar2 = 57,
SFPModule_ent11100 = 58,
RADGemini = 60,
RADArgos = 60,
};
virtual ProductID getProductID() const = 0;
@@ -343,6 +349,7 @@ public:
virtual Network getNetworkByNumber(Network::Type, size_t) const;
std::shared_ptr<HardwareInfo> getHardwareInfo(std::chrono::milliseconds timeout = std::chrono::milliseconds(100));
std::shared_ptr<MfgConfigMessage> getMfgConfig();
/**
@@ -891,7 +898,8 @@ public:
std::optional<GPTPStatus> getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100));
/* 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;
@@ -905,7 +913,19 @@ public:
void stopHeartbeat();
void restartHeartbeat();
bool iso15765Enable(const Network& network);
bool iso15765DisableAll(void);
bool iso15765TransmitMessage(const Network& network, const Iso15765MessageArgs& msg, const std::chrono::milliseconds& timeout);
bool iso15765SetupRxFlowControl(const Network& network, const Iso15765MessageArgs& msg);
protected:
using MACsecNetworkMap = std::map<Network::NetID, uint16_t>;
virtual const MACsecNetworkMap& getMACsecNetworkMap() const {
static const MACsecNetworkMap networks;
return networks;
}
bool online = false;
int messagePollingCallbackID = 0;
int internalHandlerCallbackID = 0;
@@ -1173,6 +1193,23 @@ private:
bool enableNetworkCommunication(bool enable, uint32_t timeout = 0);
bool J2534_Transaction(const Network& network, J2534CommandMessage&& msg, const std::chrono::milliseconds& timeout);
bool J2534_ClearRxFilters(const Network& network);
bool J2534_SetupCanRxFilter(const Network& network, const J2534_RxCanFilter& rxCanFilter);
bool J2534_EnableFiltering(const Network& network, const bool enable);
bool J2534_EnableIso15765(const Network& network, const bool enable);
bool J2534_ClearRxFilter(const Network& network, unsigned int iIndex);
bool J2534_EnableFirmwareUsbPassFilters(const Network& network, const bool enable);
struct NetworkHash {
size_t operator()(const Network& x) const {
return (size_t)x.getNetID();
}
};
std::unordered_map<Network, bool, NetworkHash> iso15765FirmwareEnabled;
// Keeponline (keepalive for online)
std::unique_ptr<Periodic> keeponline;
std::unique_ptr<Heartbeat> heartbeat;
+4 -4
View File
@@ -62,7 +62,7 @@ public:
RADGigastar2 = icsneoc2_devicetype_rad_gigastar2,
FIRE3_T1S_LIN = icsneoc2_devicetype_fire3_t1s_lin,
FIRE3_T1S_SENT = icsneoc2_devicetype_fire3_t1s_sent,
RADGemini = icsneoc2_devicetype_rad_gemini,
RADArgos = icsneoc2_devicetype_rad_argos,
RED = icsneoc2_devicetype_red,
ECU = icsneoc2_devicetype_ecu,
IEVB = icsneoc2_devicetype_ievb,
@@ -153,8 +153,8 @@ public:
return "RAD-EpsilonXL";
case RADMoon3:
return "RAD-Moon 3";
case RADGemini:
return "RAD-Gemini";
case RADArgos:
return "RAD-Argos";
case RADComet2:
return "RAD-Comet 2";
case RED:
@@ -281,7 +281,7 @@ private:
#define ICSNEO_DEVICETYPE_RADGIGASTAR2 ((devicetype_t)icsneoc2_devicetype_rad_gigastar2)
#define ICSNEO_DEVICETYPE_FIRE3_T1S_LIN ((devicetype_t)icsneoc2_devicetype_fire3_t1s_lin)
#define ICSNEO_DEVICETYPE_FIRE3_T1S_SENT ((devicetype_t)icsneoc2_devicetype_fire3_t1s_sent)
#define ICSNEO_DEVICETYPE_RADGEMINI ((devicetype_t)icsneoc2_devicetype_rad_gemini)
#define ICSNEO_DEVICETYPE_RADARGOS ((devicetype_t)icsneoc2_devicetype_rad_argos)
#define ICSNEO_DEVICETYPE_RED ((devicetype_t)icsneoc2_devicetype_red)
#define ICSNEO_DEVICETYPE_ECU ((devicetype_t)icsneoc2_devicetype_ecu)
#define ICSNEO_DEVICETYPE_IEVB ((devicetype_t)icsneoc2_devicetype_ievb)
@@ -132,9 +132,8 @@ protected:
virtual void setupExtensions() override {
std::vector<Network> flexRayControllers;
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));
}
virtual std::vector<std::shared_ptr<FlexRay::Controller>> getFlexRayControllers() const override {
@@ -1,19 +1,19 @@
#ifndef __RADGEMINI_H_
#define __RADGEMINI_H_
#ifndef __RADARGOS_H_
#define __RADARGOS_H_
#ifdef __cplusplus
#include "icsneo/device/device.h"
#include "icsneo/device/devicetype.h"
#include "icsneo/device/tree/radgemini/radgeminisettings.h"
#include "icsneo/device/tree/radargos/radargossettings.h"
namespace icsneo {
class RADGemini : public Device {
class RADArgos : public Device {
public:
// Serial numbers start with GE
// USB PID is 0x110E, standard driver is CDCACM
ICSNEO_FINDABLE_DEVICE(RADGemini, DeviceType::RADGemini, "GE");
ICSNEO_FINDABLE_DEVICE(RADArgos, DeviceType::RADArgos, "GE");
static const std::vector<Network>& GetSupportedNetworks() {
static std::vector<Network> supportedNetworks = {
@@ -28,11 +28,11 @@ public:
bool supportsTC10() const override { return true; }
ProductID getProductID() const override { return ProductID::RADGemini; }
ProductID getProductID() const override { return ProductID::RADArgos; }
const std::vector<ChipInfo>& getChipInfo() const override {
static std::vector<ChipInfo> chips = {
{ChipID::RADGemini_MCHIP, true, "MCHIP", "radgemini_mchip_ief", 0, FirmwareType::IEF},
{ChipID::RADArgos_MCHIP, true, "MCHIP", "radargos_mchip_ief", 0, FirmwareType::IEF},
};
return chips;
}
@@ -40,15 +40,15 @@ public:
BootloaderPipeline getBootloader() override {
return BootloaderPipeline()
.add<EnterBootloaderPhase>()
.add<FlashPhase>(ChipID::RADGemini_MCHIP, BootloaderCommunication::RED)
.add<EnterApplicationPhase>(ChipID::RADGemini_MCHIP)
.add<FlashPhase>(ChipID::RADArgos_MCHIP, BootloaderCommunication::RED)
.add<EnterApplicationPhase>(ChipID::RADArgos_MCHIP)
.add<ReconnectPhase>()
.add<WaitPhase>(std::chrono::milliseconds(3000));
}
protected:
RADGemini(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADGeminiSettings>(makeDriver);
RADArgos(neodevice_t neodevice, const driver_factory_t& makeDriver) : Device(neodevice) {
initialize<RADArgosSettings>(makeDriver);
}
void setupPacketizer(Packetizer& packetizer) override {
@@ -74,4 +74,4 @@ protected:
#endif // __cplusplus
#endif // __RADGEMINI_H_
#endif // __RADARGOS_H_
@@ -1,5 +1,5 @@
#ifndef LIBICSNEO_RADGEMINISETTINGS_H
#define LIBICSNEO_RADGEMINISETTINGS_H
#ifndef LIBICSNEO_RADARGOSSETTINGS_H
#define LIBICSNEO_RADARGOSSETTINGS_H
#include <stdint.h>
#include "icsneo/device/idevicesettings.h"
@@ -31,18 +31,18 @@ typedef struct {
uint16_t enableLatencyTest : 1;
uint16_t reserved : 15;
} flags; // 2
} radgemini_settings_t;
} radargos_settings_t;
#pragma pack(pop)
#ifdef __cplusplus
static_assert(sizeof(radgemini_settings_t) == 86, "RADGemini settings size mismatch");
static_assert(sizeof(radargos_settings_t) == 86, "RADArgos settings size mismatch");
#include <iostream>
class RADGeminiSettings : public IDeviceSettings {
class RADArgosSettings : public IDeviceSettings {
public:
RADGeminiSettings(Device* device) : IDeviceSettings(device, sizeof(radgemini_settings_t)) {}
RADArgosSettings(Device* device) : IDeviceSettings(device, sizeof(radargos_settings_t)) {}
};
}
@@ -50,4 +50,4 @@ public:
#endif // __cplusplus
#endif // LIBICSNEO_RADGEMINISETTINGS_H
#endif // LIBICSNEO_RADARGOSSETTINGS_H
@@ -70,6 +70,13 @@ public:
}
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) {
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 {
const ETHERNET10T1S_SETTINGS* t1s = getT1SSettingsFor(net);
if(t1s == nullptr)
@@ -77,6 +77,13 @@ public:
}
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) {
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 {
auto cfg = getStructurePointer<radcomet3_settings_t>();
if(cfg == nullptr)
@@ -87,9 +87,32 @@ public:
}
BootloaderPipeline pipeline;
auto compVersions = getComponentVersions();
for(size_t i = 0; i < chipVersions.size(); i++) {
const auto& version = chipVersions[i];
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip, i == 0);
auto it = compVersions.begin();
std::vector<ComponentVersion> sameIdComponents;
while(it != compVersions.end()) {
it = std::find_if(it, compVersions.end(), [&version](const auto& component) {
return (ChipID)component.identifier == version.id;
});
if (it != compVersions.end()) {
sameIdComponents.push_back(*it);
it++;
}
}
if (sameIdComponents.size() > 1) {
std::vector<ComponentVersion> tempCompVersions;
for (const auto& component : compVersions) {
if ((ChipID)component.identifier != version.id || component.expansionSlot != sameIdComponents[0].expansionSlot) {
tempCompVersions.push_back(component);
}
}
compVersions = std::move(tempCompVersions);
}
if (!sameIdComponents.empty()) {
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip, i == 0, true, true, sameIdComponents[0].expansionSlot);
}
}
pipeline.add<EnterApplicationPhase>(mainChipID);
pipeline.add<WaitPhase>(std::chrono::milliseconds(3000));
@@ -183,6 +206,7 @@ protected:
Network::NetID::LIN_01,
Network::NetID::FLEXRAY_01,
Network::NetID::FLEXRAY_01A,
Network::NetID::FLEXRAY_01B,
@@ -171,9 +171,32 @@ public:
}
BootloaderPipeline pipeline;
auto compVersions = getComponentVersions();
for(size_t i = 0; i < chipVersions.size(); i++) {
const auto& version = chipVersions[i];
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip, i == 0);
auto it = compVersions.begin();
std::vector<ComponentVersion> sameIdComponents;
while(it != compVersions.end()) {
it = std::find_if(it, compVersions.end(), [&version](const auto& component) {
return (ChipID)component.identifier == version.id;
});
if (it != compVersions.end()) {
sameIdComponents.push_back(*it);
it++;
}
}
if (sameIdComponents.size() > 1) {
std::vector<ComponentVersion> tempCompVersions;
for (const auto& component : compVersions) {
if ((ChipID)component.identifier != version.id || component.expansionSlot != sameIdComponents[0].expansionSlot) {
tempCompVersions.push_back(component);
}
}
compVersions = std::move(tempCompVersions);
}
if (!sameIdComponents.empty()) {
pipeline.add<FlashPhase>(version.id, BootloaderCommunication::RADMultiChip, i == 0, true, true, sameIdComponents[0].expansionSlot);
}
}
pipeline.add<EnterApplicationPhase>(mainChipID);
pipeline.add<WaitPhase>(std::chrono::milliseconds(3000));
@@ -217,6 +240,14 @@ public:
return chipVersions;
}
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)
{
initialize<RADGigastar2Settings, Disk::ExtExtractorDiskReadDriver, Disk::NeoMemoryDiskDriver>(makeDriver);
@@ -38,6 +38,13 @@ public:
.add<ReconnectPhase>();
}
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) {
initialize<RADMoon2Settings>(makeDriver);
}
@@ -52,6 +52,14 @@ public:
.add<ReconnectPhase>();
}
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) {
initialize<RADMoon3Settings>(makeDriver);
}
+9 -9
View File
@@ -280,7 +280,7 @@ typedef unsigned __int64 uint64_t;
#define NEODEVICE_GIGASTAR2 (0x00000029)
#define NEODEVICE_FIRE3_T1S_LIN (0x0000002A)
#define NEODEVICE_FIRE3_T1S_SENT (0x0000002B)
#define NEODEVICE_RADGEMINI (0x0000002C)
#define NEODEVICE_RADARGOS (0x0000002C)
#define NEODEVICE_RED_DEPRECATED (0x00000040)
#define NEODEVICE_ECU_DEPRECATED (0x00000080)
@@ -975,7 +975,7 @@ typedef union _stChipVersions
{
uint8_t mchip_major;
uint8_t mchip_minor;
} radgemini_versions;
} radargos_versions;
struct
{
@@ -2794,7 +2794,7 @@ typedef struct _SRADMoon3Settings
#define SRADMoon3Settings_SIZE 68
typedef struct _SRADGeminiSettings
typedef struct _SRADArgosSettings
{
uint16_t perf_en; // 2
@@ -2815,9 +2815,9 @@ typedef struct _SRADGeminiSettings
uint16_t enableLatencyTest : 1;
uint16_t reserved : 15;
} flags; // 2
} SRADGeminiSettings;
} SRADArgosSettings;
#define SRADGeminiSettings_SIZE 86
#define SRADArgosSettings_SIZE 86
typedef struct _SRADGigastarSettings
{
@@ -4450,7 +4450,7 @@ typedef struct _GLOBAL_SETTINGS
SRADEpsilonSettings epsilon;
SRADBMSSettings rad_bms;
SRADMoon3Settings radmoon3;
SRADGeminiSettings radgemini;
SRADArgosSettings radargos;
SRADCometSettings radcomet;
SRADComet3Settings radcomet3;
SRADGigastar2Settings radgigastar2;
@@ -4509,7 +4509,7 @@ typedef enum _EDeviceSettingsType
DeviceRADGalaxy2SettingsType,
DeviceRADGigastar2SettingsType,
DeviceRADMoonT1SSettingsType,
DeviceRADGeminiSettingsType,
DeviceRADArgosSettingsType,
DeviceFire3T1sLinSettingsType,
// add new settings type here
// Also add to map inside cicsneoVI::Init()
@@ -4545,7 +4545,7 @@ typedef struct _SDeviceSettings
SRADEpsilonSettings epsilon;
SRADBMSSettings rad_bms;
SRADMoon3Settings radmoon3;
SRADGeminiSettings radgemini;
SRADArgosSettings radargos;
SFire3FlexraySettings fire3Flexray;
SFire3T1sLinSettings fire3t1slin;
SRADCometSettings radcomet;
@@ -5430,7 +5430,7 @@ CHECK_STRUCT_SIZE(SRADEpsilonSettings);
CHECK_STRUCT_SIZE(RAD_GPTP_SETTINGS);
CHECK_STRUCT_SIZE(SRADBMSSettings);
CHECK_STRUCT_SIZE(SRADMoon3Settings);
CHECK_STRUCT_SIZE(SRADGeminiSettings);
CHECK_STRUCT_SIZE(SRADArgosSettings);
CHECK_STRUCT_SIZE(SFire3FlexraySettings);
CHECK_STRUCT_SIZE(SFire3T1sLinSettings);
CHECK_STRUCT_SIZE(CANHubSettings);
+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_update_responder = 5,
icsneoc2_lin_msg_type_error = 6,
icsneoc2_lin_msg_type_wakeup_request = 7,
} _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_BUS_RECOVERED 0x40
#define ICSNEOC2_LIN_STATUS_BREAK_ONLY 0x80
#define ICSNEOC2_LIN_STATUS_WAKEUP_REQUEST 0x100
typedef uint32_t icsneoc2_lin_status_flags_t;
+2 -2
View File
@@ -52,7 +52,7 @@ typedef enum _icsneoc2_devicetype_t {
icsneoc2_devicetype_rad_gigastar2 = 0x00000029,
icsneoc2_devicetype_fire3_t1s_lin = 0x0000002a,
icsneoc2_devicetype_fire3_t1s_sent = 0x0000002b,
icsneoc2_devicetype_rad_gemini = 0x0000002c,
icsneoc2_devicetype_rad_argos = 0x0000002c,
icsneoc2_devicetype_red = 0x00000040,
icsneoc2_devicetype_ecu = 0x00000080,
icsneoc2_devicetype_ievb = 0x00000100,
@@ -678,7 +678,7 @@ typedef enum _icsneoc2_chip_id_t {
icsneoc2_chip_id_radmoont1s_zchip = 130,
icsneoc2_chip_id_radgigastar2_zynq = 131,
icsneoc2_chip_id_sfpmodule_ent11100_mchip = 132,
icsneoc2_chip_id_radgemini_mchip = 135,
icsneoc2_chip_id_radargos_mchip = 135,
icsneoc2_chip_id_maxsize, // Must be last entry, Don't use as a chip ID.
// Used for unknown or invalid chip ID
+1 -1
View File
@@ -28,7 +28,7 @@
#include "icsneo/device/tree/radmoon2/radmoon2.h"
#include "icsneo/device/tree/radmoon2/radmoon2zl.h"
#include "icsneo/device/tree/radmoon3/radmoon3.h"
#include "icsneo/device/tree/radgemini/radgemini.h"
#include "icsneo/device/tree/radargos/radargos.h"
#include "icsneo/device/tree/radmoonduo/radmoonduo.h"
#include "icsneo/device/tree/radpluto/radpluto.h"
#include "icsneo/device/tree/radstar2/radstar2.h"
+1
View File
@@ -35,6 +35,7 @@ private:
Socket messageSocket;
bool opened = false;
bool comEnabled = false;
std::string token;
std::unique_ptr<Socket> dataSocket;
};
+1 -1
View File
@@ -28,7 +28,7 @@
#include "icsneo/device/tree/radmoon2/radmoon2.h"
#include "icsneo/device/tree/radmoon2/radmoon2zl.h"
#include "icsneo/device/tree/radmoon3/radmoon3.h"
#include "icsneo/device/tree/radgemini/radgemini.h"
#include "icsneo/device/tree/radargos/radargos.h"
#include "icsneo/device/tree/radmoonduo/radmoonduo.h"
#include "icsneo/device/tree/radpluto/radpluto.h"
#include "icsneo/device/tree/radstar2/radstar2.h"
+1 -1
View File
@@ -86,7 +86,7 @@ void CDCACM::Find(std::vector<FoundDevice>& found) {
if(ref == nullptr)
return;
io_iterator_t matchingServices = 0;
kern_return_t kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, ref, &matchingServices);
kern_return_t kernResult = IOServiceGetMatchingServices(kIOMainPortDefault, ref, &matchingServices);
if(KERN_SUCCESS != kernResult || matchingServices == 0)
return;
IOReleaser matchingServicesReleaser(matchingServices);
+40 -13
View File
@@ -6,9 +6,21 @@
using namespace icsneo;
#define SERVD_VERSION 2
#define SERVD_VERSION 3
static const Address SERVD_ADDRESS = [] {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
const auto envip = std::getenv("LIBICSNEO_SERVD_IP");
const auto envport = std::getenv("LIBICSNEO_SERVD_PORT");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
return Address(envip ? envip : "127.0.0.1", envport ? static_cast<uint16_t>(std::stoi(envport)) : 26741);
}();
static const Address SERVD_ADDRESS = Address("127.0.0.1", 26741);
static const std::string SERVD_VERSION_STR = std::to_string(SERVD_VERSION);
bool Servd::Enabled() {
@@ -56,10 +68,15 @@ void Servd::Find(std::vector<FoundDevice>& found) {
return;
}
try {
if(std::stoll(response) < SERVD_VERSION) {
EventManager::GetInstance().add(APIEvent::Type::ServdOutdatedError, APIEvent::Severity::Error);
return;
}
} catch (const std::exception&) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
return;
}
response.resize(512);
const std::string find_request = SERVD_VERSION_STR + " find";
@@ -70,22 +87,25 @@ void Servd::Find(std::vector<FoundDevice>& found) {
const auto lines = split(response, '\n');
for(auto&& line : lines) {
const auto cols = split(line, ' ');
if(cols.size() < 3) {
if(cols.size() < 2) {
if(!line.empty()) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
}
continue;
}
const auto& serial = cols[0];
const auto& ip = cols[1];
if(serial.empty() || serial.size() >= sizeof(FoundDevice::serial)) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
continue;
}
uint16_t port = 0;
try {
port = static_cast<uint16_t>(std::stoi(cols[2]));
port = static_cast<uint16_t>(std::stoi(cols[1]));
} catch (const std::exception&) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
continue;
}
Address address(ip.c_str(), port);
Address address(SERVD_ADDRESS.ip().c_str(), port);
auto& newFound = found.emplace_back();
std::copy(serial.begin(), serial.end(), newFound.serial);
newFound.makeDriver = [=](device_eventhandler_t err, neodevice_t& forDevice) {
@@ -130,16 +150,19 @@ bool Servd::open() {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
return false;
}
const auto& ip = tokens[0];
uint16_t port = 0;
try {
port = static_cast<uint16_t>(std::stoi(tokens[1]));
port = static_cast<uint16_t>(std::stoi(tokens[0]));
} catch (const std::exception&) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
return false;
}
Address address(ip.c_str(), port);
dataSocket->connect(address);
token = tokens[1];
Address address(SERVD_ADDRESS.ip().c_str(), port);
if(!dataSocket->connect(address)) {
EventManager::GetInstance().add(APIEvent::Type::SyscallError, APIEvent::Severity::Error);
return false;
}
readThread = std::thread(&Servd::read, this);
writeThread = std::thread(&Servd::write, this);
opened = true;
@@ -159,15 +182,14 @@ bool Servd::close() {
writeThread.join();
}
if(isOpen()) {
Address localAddress;
dataSocket->address(localAddress);
const std::string request = SERVD_VERSION_STR + " close " + localAddress.ip() + " " + std::to_string(localAddress.port());
const std::string request = SERVD_VERSION_STR + " close " + token;
std::string response;
response.resize(1);
if(!messageSocket.transceive(request, response, std::chrono::milliseconds(5000))) {
EventManager::GetInstance().add(APIEvent::Type::ServdTransceiveError, APIEvent::Severity::Error);
return false;
}
token.clear();
dataSocket.reset();
}
opened = false;
@@ -207,7 +229,12 @@ bool Servd::enableCommunication(bool enable, bool& sendMsg) {
EventManager::GetInstance().add(APIEvent::Type::ServdTransceiveError, APIEvent::Severity::Error);
return false;
}
try {
com = response.empty() ? 0 : std::stoll(response);
} catch (const std::exception&) {
EventManager::GetInstance().add(APIEvent::Type::ServdInvalidResponseError, APIEvent::Severity::Error);
return false;
}
}
sendMsg = false;
if(enable) {
+111
View File
@@ -0,0 +1,111 @@
#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, KnownWireBytesAndStatus) {
for(bool clause45 : {false, true}) {
auto msg = request(clause45, true);
EXPECT_FALSE(msg.messages[0]->Status.has_value());
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}));
for(uint8_t status = 0; status < 8; ++status) {
bytes[4] = static_cast<uint8_t>((clause45 ? 7 : 3) | (status << 3));
auto decoded = HardwareEthernetPhyRegisterPacket::DecodeToMessage(bytes, ignore);
ASSERT_NE(decoded, nullptr);
EXPECT_EQ(decoded->messages[0]->Status, status);
EXPECT_EQ(encode(*decoded)[4], clause45 ? 7 : 3); // never retransmit response status
}
}
}
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);
}
+8 -5
View File
@@ -480,7 +480,7 @@ TEST(icsneoc2, test_icsneoc2_devicetype_t)
ASSERT_EQ(icsneoc2_devicetype_rad_gigastar2, 0x00000029);
ASSERT_EQ(icsneoc2_devicetype_fire3_t1s_lin, 0x0000002a);
ASSERT_EQ(icsneoc2_devicetype_fire3_t1s_sent, 0x0000002b);
ASSERT_EQ(icsneoc2_devicetype_rad_gemini, 0x0000002c);
ASSERT_EQ(icsneoc2_devicetype_rad_argos, 0x0000002c);
ASSERT_EQ(icsneoc2_devicetype_red, 0x00000040);
ASSERT_EQ(icsneoc2_devicetype_ecu, 0x00000080);
ASSERT_EQ(icsneoc2_devicetype_ievb, 0x00000100);
@@ -543,7 +543,7 @@ TEST(icsneoc2, test_devicetype_enum_alignment)
ASSERT_EQ(icsneo::DeviceType::RADGigastar2, icsneoc2_devicetype_rad_gigastar2);
ASSERT_EQ(icsneo::DeviceType::FIRE3_T1S_LIN, icsneoc2_devicetype_fire3_t1s_lin);
ASSERT_EQ(icsneo::DeviceType::FIRE3_T1S_SENT, icsneoc2_devicetype_fire3_t1s_sent);
ASSERT_EQ(icsneo::DeviceType::RADGemini, icsneoc2_devicetype_rad_gemini);
ASSERT_EQ(icsneo::DeviceType::RADArgos, icsneoc2_devicetype_rad_argos);
ASSERT_EQ(icsneo::DeviceType::RED, icsneoc2_devicetype_red);
ASSERT_EQ(icsneo::DeviceType::ECU, icsneoc2_devicetype_ecu);
ASSERT_EQ(icsneo::DeviceType::IEVB, icsneoc2_devicetype_ievb);
@@ -947,7 +947,7 @@ TEST(icsneoc2, test_icsneoc2_chip_id_t)
ASSERT_EQ(icsneoc2_chip_id_radmoont1s_zchip, 130);
ASSERT_EQ(icsneoc2_chip_id_radgigastar2_zynq, 131);
ASSERT_EQ(icsneoc2_chip_id_sfpmodule_ent11100_mchip, 132);
ASSERT_EQ(icsneoc2_chip_id_radgemini_mchip, 135);
ASSERT_EQ(icsneoc2_chip_id_radargos_mchip, 135);
ASSERT_EQ(icsneoc2_chip_id_maxsize, 136);
ASSERT_EQ(icsneoc2_chip_id_invalid, 255);
@@ -1084,7 +1084,7 @@ TEST(icsneoc2, test_chip_id_enum_alignment)
ASSERT_EQ(static_cast<icsneoc2_chip_id_t>(icsneo::ChipID::RADMOONT1S_ZCHIP), icsneoc2_chip_id_radmoont1s_zchip);
ASSERT_EQ(static_cast<icsneoc2_chip_id_t>(icsneo::ChipID::RADGigastar2_ZYNQ), icsneoc2_chip_id_radgigastar2_zynq);
ASSERT_EQ(static_cast<icsneoc2_chip_id_t>(icsneo::ChipID::SFPModule_ent11100_MCHIP), icsneoc2_chip_id_sfpmodule_ent11100_mchip);
ASSERT_EQ(static_cast<icsneoc2_chip_id_t>(icsneo::ChipID::RADGemini_MCHIP), icsneoc2_chip_id_radgemini_mchip);
ASSERT_EQ(static_cast<icsneoc2_chip_id_t>(icsneo::ChipID::RADArgos_MCHIP), icsneoc2_chip_id_radargos_mchip);
ASSERT_EQ(static_cast<icsneoc2_chip_id_t>(icsneo::ChipID::Invalid), icsneoc2_chip_id_invalid);
}
@@ -1113,7 +1113,7 @@ TEST(icsneoc2, test_icsneoc2_chip_versions_props_get)
{
// Build an in-memory list of two chip_versions nodes
icsneoc2_chip_versions_t second{};
second.version_report.id = icsneo::ChipID::RADGemini_MCHIP;
second.version_report.id = icsneo::ChipID::RADArgos_MCHIP;
second.version_report.name = "second";
second.version_report.major = 9;
second.version_report.minor = 8;
@@ -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_update_responder, 5);
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));
}
@@ -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_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_WAKEUP_REQUEST), icsneoc2_lin_msg_type_wakeup_request);
}
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_BUS_RECOVERED, 0x40);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_BREAK_ONLY, 0x80);
ASSERT_EQ(ICSNEOC2_LIN_STATUS_WAKEUP_REQUEST, 0x100);
}
TEST(icsneoc2, test_icsneoc2_eth_create)
+77
View File
@@ -2,12 +2,14 @@
#include "icsneo/communication/encoder.h"
#include "icsneo/communication/packet/linpacket.h"
#include "icsneo/communication/message/linmessage.h"
#include "icsneo/communication/message/transmitmessage.h"
#include "icsneo/communication/packetizer.h"
#include "icsneo/core/ringbuffer.h"
#include "icsneo/api/eventmanager.h"
#include "gtest/gtest.h"
#include <vector>
#include <iostream>
#include <cstring>
using namespace icsneo;
@@ -55,6 +57,16 @@ protected:
0x00, 0x00,
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 =
{0xaa, 0x0c, 0x22, 0x00,
0x10, 0x00, 0x88, 0x03,
@@ -139,6 +151,29 @@ TEST_F(LINEncoderDecoderTest, PacketEncoderControllerHeaderTest) {
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) {
std::vector<uint8_t> bytestream;
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->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
+221
View File
@@ -0,0 +1,221 @@
#include "gtest/gtest.h"
#include <cstring>
#include <memory>
#include "icsneo/icsneocpp.h"
#include "icsneo/communication/driver.h"
#include "icsneo/communication/message/extendedresponsemessage.h"
#include "icsneo/communication/message/filter/extendedresponsefilter.h"
#include "icsneo/communication/message/tc10statusmessage.h"
#include "icsneo/device/tree/radmoon2/radmoon2.h"
#include "icsneo/device/tree/radmoon2/radmoon2zl.h"
using namespace icsneo;
namespace {
class TC10TestDriver : public Driver {
public:
explicit TC10TestDriver(const device_eventhandler_t& handler) : Driver(handler) {}
bool open() override { opened = true; return true; }
bool isOpen() override { return opened; }
bool close() override { opened = false; return true; }
driver_finder_t getFinder() override { return [](std::vector<FoundDevice>&) {}; }
int writes = 0;
// Replies pushed, in order, when the host writes a command.
std::vector<std::vector<uint8_t>> replies;
protected:
bool writeInternal(const std::vector<uint8_t>&) override {
++writes;
for(const auto& reply : replies)
pushRx(reply.data(), reply.size());
replies.clear();
return true;
}
private:
bool opened = false;
};
std::vector<uint8_t> longPacket(Network::NetID netid, const void* payload, size_t payloadSize) {
const uint16_t packetLength = static_cast<uint16_t>(6 + payloadSize);
std::vector<uint8_t> bytes(packetLength);
bytes[0] = 0xAA;
bytes[1] = 0x00;
bytes[2] = static_cast<uint8_t>(packetLength & 0xff);
bytes[3] = static_cast<uint8_t>((packetLength >> 8) & 0xff);
const auto id = static_cast<uint16_t>(netid);
bytes[4] = static_cast<uint8_t>(id & 0xff);
bytes[5] = static_cast<uint8_t>((id >> 8) & 0xff);
std::memcpy(bytes.data() + 6, payload, payloadSize);
return bytes;
}
std::vector<uint8_t> genericReturn(ExtendedCommand command, ExtendedResponse code) {
ExtendedResponseMessage::PackedGenericResponse packed{};
packed.header.command = ExtendedCommand::GenericReturn;
packed.header.length = static_cast<uint16_t>(sizeof(packed) - sizeof(packed.header));
packed.command = command;
packed.returnCode = code;
return longPacket(Network::NetID::ExtendedCommand, &packed, sizeof(packed));
}
// Extended body of a GetTC10Status reply. `tail` is extra payload past the two status bytes.
std::vector<uint8_t> statusBody(uint8_t wake, uint8_t sleep, std::initializer_list<uint8_t> tail = {}) {
const auto payloadLength = static_cast<uint16_t>(2 + tail.size());
std::vector<uint8_t> body = {
0x3f, 0x00,
static_cast<uint8_t>(payloadLength & 0xff),
static_cast<uint8_t>((payloadLength >> 8) & 0xff),
wake,
sleep,
};
body.insert(body.end(), tail);
return body;
}
class OpenTC10Device {
public:
TC10TestDriver* driver = nullptr;
std::shared_ptr<RADMoon2ZL> device;
OpenTC10Device() {
FoundDevice found;
std::memcpy(found.serial, "RN0001", 6);
found.makeDriver = [this](device_eventhandler_t handler, neodevice_t&) {
auto result = std::make_unique<TC10TestDriver>(handler);
driver = result.get();
return result;
};
device = std::make_shared<RADMoon2ZL>(found);
device->com->readTaskWakeTimeout = std::chrono::milliseconds(20);
EXPECT_TRUE(device->com->open());
}
};
FoundDevice moon2Found() {
FoundDevice found;
std::memcpy(found.serial, "RM0001", 6);
found.makeDriver = [](device_eventhandler_t handler, neodevice_t&) {
return std::make_unique<TC10TestDriver>(handler);
};
return found;
}
}
TEST(TC10, WakeFilterMatchesOnlyThatCommand) {
ExtendedResponseFilter filter(ExtendedCommand::RequestTC10Wake);
EXPECT_TRUE(filter.match(std::make_shared<ExtendedResponseMessage>(
ExtendedCommand::RequestTC10Wake, ExtendedResponse::OperationFailed)));
EXPECT_FALSE(filter.match(std::make_shared<ExtendedResponseMessage>(
ExtendedCommand::RequestTC10Sleep, ExtendedResponse::OK)));
EXPECT_FALSE(filter.match(std::make_shared<ExtendedResponseMessage>(
ExtendedCommand::GetDiskDetails, ExtendedResponse::OK)));
}
TEST(TC10, SleepFilterMatchesOnlyThatCommand) {
ExtendedResponseFilter filter(ExtendedCommand::RequestTC10Sleep);
EXPECT_TRUE(filter.match(std::make_shared<ExtendedResponseMessage>(
ExtendedCommand::RequestTC10Sleep, ExtendedResponse::OK)));
EXPECT_FALSE(filter.match(std::make_shared<ExtendedResponseMessage>(
ExtendedCommand::RequestTC10Wake, ExtendedResponse::OK)));
}
TEST(TC10, UnsupportedDeviceReportsNotSupported) {
auto device = std::make_shared<RADMoon2>(moon2Found());
EXPECT_FALSE(device->requestTC10Wake(Network::NetID::AE_01));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NotSupported);
EXPECT_FALSE(device->requestTC10Sleep(Network::NetID::AE_01));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NotSupported);
EXPECT_FALSE(device->getTC10Status(Network::NetID::AE_01).has_value());
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NotSupported);
}
TEST(TC10, WakeAcceptsItsOwnOk) {
OpenTC10Device tc10;
(void)GetLastError();
tc10.driver->replies = {
genericReturn(ExtendedCommand::RequestTC10Sleep, ExtendedResponse::OperationFailed),
genericReturn(ExtendedCommand::RequestTC10Wake, ExtendedResponse::OK),
};
EXPECT_TRUE(tc10.device->requestTC10Wake(Network::NetID::AE_02));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EXPECT_EQ(tc10.driver->writes, 1);
}
TEST(TC10, SleepAcceptsItsOwnOk) {
OpenTC10Device tc10;
(void)GetLastError();
tc10.driver->replies = {
genericReturn(ExtendedCommand::RequestTC10Wake, ExtendedResponse::OperationFailed),
genericReturn(ExtendedCommand::RequestTC10Sleep, ExtendedResponse::OK),
};
EXPECT_TRUE(tc10.device->requestTC10Sleep(Network::NetID::AE_01));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EXPECT_EQ(tc10.driver->writes, 1);
}
TEST(TC10, WakeReportsDeviceRejection) {
OpenTC10Device tc10;
tc10.driver->replies = {
genericReturn(ExtendedCommand::RequestTC10Sleep, ExtendedResponse::OK),
genericReturn(ExtendedCommand::RequestTC10Wake, ExtendedResponse::OperationFailed),
};
EXPECT_FALSE(tc10.device->requestTC10Wake(Network::NetID::AE_02));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::TC10RequestFailed);
EXPECT_EQ(tc10.driver->writes, 1);
}
TEST(TC10, SleepReportsDeviceRejection) {
OpenTC10Device tc10;
tc10.driver->replies = {
genericReturn(ExtendedCommand::RequestTC10Wake, ExtendedResponse::OK),
genericReturn(ExtendedCommand::RequestTC10Sleep, ExtendedResponse::InvalidParameter),
};
EXPECT_FALSE(tc10.device->requestTC10Sleep(Network::NetID::AE_01));
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::TC10RequestFailed);
EXPECT_EQ(tc10.driver->writes, 1);
}
TEST(TC10Status, DecodesTheStatusPair) {
auto msg = TC10StatusMessage::DecodeToMessage(statusBody(1, 1));
ASSERT_NE(msg, nullptr);
EXPECT_EQ(msg->wakeStatus, TC10WakeStatus::WakeReceived);
EXPECT_EQ(msg->sleepStatus, TC10SleepStatus::SleepReceived);
}
TEST(TC10Status, RejectsTruncatedOrForeignPayloads) {
EXPECT_EQ(TC10StatusMessage::DecodeToMessage({}), nullptr);
auto bytes = statusBody(0, 0);
EXPECT_EQ(TC10StatusMessage::DecodeToMessage({bytes.begin(), bytes.begin() + 5}), nullptr);
std::vector<uint8_t> shortLength = {0x3f, 0x00, 0x01, 0x00, 0x00, 0x00};
EXPECT_EQ(TC10StatusMessage::DecodeToMessage(shortLength), nullptr);
std::vector<uint8_t> foreign = {0x3d, 0x00, 0x02, 0x00, 0x00, 0x00};
EXPECT_EQ(TC10StatusMessage::DecodeToMessage(foreign), nullptr);
}
TEST(TC10Status, DropsBytesAfterTheStatusPair) {
// Tail is little-endian AE_02 (37). The decoded message has no network, so this still succeeds.
auto msg = TC10StatusMessage::DecodeToMessage(statusBody(0, 1, {37, 0}));
ASSERT_NE(msg, nullptr);
EXPECT_EQ(msg->wakeStatus, TC10WakeStatus::NoWakeReceived);
EXPECT_EQ(msg->sleepStatus, TC10SleepStatus::SleepReceived);
}
TEST(TC10, StatusReturnsTheDecodedPair) {
OpenTC10Device tc10;
(void)GetLastError();
const auto body = statusBody(1, 0);
tc10.driver->replies = {longPacket(Network::NetID::ExtendedCommand, body.data(), body.size())};
const auto status = tc10.device->getTC10Status(Network::NetID::AE_01);
ASSERT_TRUE(status.has_value());
EXPECT_EQ(status->wakeStatus, TC10WakeStatus::WakeReceived);
EXPECT_EQ(status->sleepStatus, TC10SleepStatus::NoSleepReceived);
EXPECT_EQ(GetLastError().getType(), APIEvent::Type::NoErrorFound);
EXPECT_EQ(tc10.driver->writes, 1);
}