4 Commits
18 changed files with 268 additions and 11 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
+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;
}
+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()
@@ -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
+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);
@@ -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:
+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:
+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()
@@ -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);
@@ -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];
@@ -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)
@@ -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)
+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;
+3
View File
@@ -1862,6 +1862,7 @@ TEST(icsneoc2, test_lin_msg_type_enum_values)
ASSERT_EQ(icsneoc2_lin_msg_type_sync_only, 4);
ASSERT_EQ(icsneoc2_lin_msg_type_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);
}