Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/CANMODULE-UTILS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ high_speed
timeout
vcan
sent_acknowledgement
operating_mode
```

Hyphenated key spelling is also accepted, for example `--set enable-termination=true`.
Expand Down
16 changes: 16 additions & 0 deletions src/include/CanDeviceConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,21 @@ struct CanDeviceConfiguration {
*/
std::optional<uint32_t> sent_acknowledgement;

/**
* @brief The operating mode of the CAN bus.
*
* This parameter is optional and only has effect for Anagate devices. It
* defaults to 0 if unset. The accepted values are:
* - 0 = default mode.
* - 1 = loop back mode: no telegrams are sent via the CAN bus, they are
* instead received as if they had been transmitted over CAN by a
* different CAN device.
* - 2 = listen mode: the device operates as a passive bus partner, meaning
* no telegrams are sent to the CAN bus (nor ACKs for incoming telegrams).
* - 3 = offline mode: no telegrams are sent or received on the CAN bus.
*/
std::optional<uint32_t> operating_mode;

std::string to_string() const noexcept;

/**
Expand Down Expand Up @@ -153,6 +168,7 @@ inline const std::vector<FieldDescriptor>& fields() {
{"timeout", &CanDeviceConfiguration::timeout},
{"vcan", &CanDeviceConfiguration::vcan},
{"sent_acknowledgement", &CanDeviceConfiguration::sent_acknowledgement},
{"operating_mode", &CanDeviceConfiguration::operating_mode},
};
return kFields;
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/CanVendorAnagate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const std::set<std::string> CanVendorAnagate::accepted_parameters = {
"bus_number", "host",
"bitrate", "enable_termination",
"high_speed", "sent_acknowledgement",
"timeout"};
"timeout", "operating_mode"};

/**
* @brief Callback function to handle incoming CAN frames from the AnaGate DLL.
Expand Down Expand Up @@ -120,6 +120,9 @@ CanReturnCode CanVendorAnagate::vendor_open() noexcept {
high_speed = args().config.high_speed.value();
}

operating_mode =
static_cast<AnaUInt8>(args().config.operating_mode.value_or(0));

// Set the modified configuration
CANSetGlobals(m_handle, bitrate, operating_mode, enable_termination,
high_speed, enable_timestamp);
Expand Down
1 change: 1 addition & 0 deletions src/python/CanModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ PYBIND11_MODULE(canmodule, m) {
.def_readwrite("timeout", &CanDeviceConfiguration::timeout)
.def_readwrite("sent_acknowledgement",
&CanDeviceConfiguration::sent_acknowledgement)
.def_readwrite("operating_mode", &CanDeviceConfiguration::operating_mode)
.def("__str__", &CanDeviceConfiguration::to_string);

py::class_<CanDiagnostics>(m, "CanDiagnostics")
Expand Down
10 changes: 9 additions & 1 deletion test/cpp/CanDeviceConfiguration_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ TEST_F(CanDeviceConfigurationTest, DefaultConstructorLeavesEverythingUnset) {
ASSERT_FALSE(config.timeout.has_value());
ASSERT_FALSE(config.vcan.has_value());
ASSERT_FALSE(config.sent_acknowledgement.has_value());
ASSERT_FALSE(config.operating_mode.has_value());
}

TEST_F(CanDeviceConfigurationTest, AssignsEveryParameterOfTheMap) {
Expand All @@ -35,6 +36,7 @@ TEST_F(CanDeviceConfigurationTest, AssignsEveryParameterOfTheMap) {
{"timeout", "6000"},
{"vcan", "true"},
{"sent_acknowledgement", "1"},
{"operating_mode", "2"},
});

ASSERT_EQ(config.bus_name.value(), "can0");
Expand All @@ -46,6 +48,7 @@ TEST_F(CanDeviceConfigurationTest, AssignsEveryParameterOfTheMap) {
ASSERT_EQ(config.timeout.value(), 6000);
ASSERT_TRUE(config.vcan.value());
ASSERT_EQ(config.sent_acknowledgement.value(), 1);
ASSERT_EQ(config.operating_mode.value(), 2);
}

TEST_F(CanDeviceConfigurationTest, LeavesTheAbsentParametersUnset) {
Expand All @@ -61,11 +64,12 @@ TEST_F(CanDeviceConfigurationTest, LeavesTheAbsentParametersUnset) {
ASSERT_FALSE(config.timeout.has_value());
ASSERT_FALSE(config.vcan.has_value());
ASSERT_FALSE(config.sent_acknowledgement.has_value());
ASSERT_FALSE(config.operating_mode.has_value());
}

TEST_F(CanDeviceConfigurationTest, AssignsEveryParameterPositionally) {
const CanDeviceConfiguration config{"can0", 2, "127.0.0.1", 125000, true,
false, 6000, true, 1};
false, 6000, true, 1, 2};

ASSERT_EQ(config.bus_name.value(), "can0");
ASSERT_EQ(config.bus_number.value(), 2);
Expand All @@ -76,6 +80,7 @@ TEST_F(CanDeviceConfigurationTest, AssignsEveryParameterPositionally) {
ASSERT_EQ(config.timeout.value(), 6000);
ASSERT_TRUE(config.vcan.value());
ASSERT_EQ(config.sent_acknowledgement.value(), 1);
ASSERT_EQ(config.operating_mode.value(), 2);
}

TEST_F(CanDeviceConfigurationTest, LeavesTrailingPositionalParametersUnset) {
Expand All @@ -90,6 +95,7 @@ TEST_F(CanDeviceConfigurationTest, LeavesTrailingPositionalParametersUnset) {
ASSERT_FALSE(config.timeout.has_value());
ASSERT_FALSE(config.vcan.has_value());
ASSERT_FALSE(config.sent_acknowledgement.has_value());
ASSERT_FALSE(config.operating_mode.has_value());
}

TEST_F(CanDeviceConfigurationTest, RejectsUnknownParameters) {
Expand Down Expand Up @@ -117,6 +123,8 @@ TEST_F(CanDeviceConfigurationTest, RejectsValuesOfTheWrongType) {
{"high_speed", "TRUE"},
{"vcan", "1"},
{"sent_acknowledgement", "abc"},
{"operating_mode", "-1"},
{"operating_mode", "abc"},
};

for (const auto& [key, value] : invalid_values) {
Expand Down
25 changes: 25 additions & 0 deletions test/python/test_anagate.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,31 @@ def test_anagate_diagnostics():
)


def test_anagate_operating_mode():
canDeviceConfig = CanDeviceConfiguration()
canDeviceConfig.host = DEVICE_ONE.host
canDeviceConfig.bus_number = DEVICE_ONE.bus_number
canDeviceConfig.bitrate = DEVICE_ONE.bitrate
canDeviceConfig.enable_termination = DEVICE_ONE.enable_termination
canDeviceConfig.high_speed = DEVICE_ONE.high_speed
canDeviceConfig.operating_mode = 1

myDevice1 = CanDevice.create("anagate", CanDeviceArguments(canDeviceConfig))
try:
r = myDevice1.open()
assert r == CanReturnCode.success

diag = myDevice1.diagnostics()
assert diag.mode == "LOOPBACK"
finally:
myDevice1.close()

canDeviceConfig.operating_mode = 0
myDevice1 = CanDevice.create("anagate", CanDeviceArguments(canDeviceConfig))
myDevice1.open()
myDevice1.close()


def test_anagate_bus_off_recovery():
received_frames_dev1 = []
myDevice1 = CanDevice.create(
Expand Down
2 changes: 2 additions & 0 deletions test/python/test_canmodule_utils_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ def test_build_can_device_configuration_sets_all_supported_fields():
"high_speed": "false",
"timeout": "6000",
"sent_acknowledgement": "1",
"operating_mode": "2",
}
)

Expand All @@ -174,3 +175,4 @@ def test_build_can_device_configuration_sets_all_supported_fields():
assert configuration.high_speed is False
assert configuration.timeout == 6000
assert configuration.sent_acknowledgement == 1
assert configuration.operating_mode == 2