Skip to content
Open
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
27 changes: 21 additions & 6 deletions api/CanMsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ class CanMsg : public Printable
static uint8_t constexpr MAX_DATA_LENGTH = 8;

static uint32_t constexpr CAN_EFF_FLAG = 0x80000000U;
static uint32_t constexpr CAN_RTR_FLAG = 0x40000000U; /* remote transmission request (RTR) */
static uint32_t constexpr CAN_SFF_MASK = 0x000007FFU; /* standard frame format (SFF) */
static uint32_t constexpr CAN_EFF_MASK = 0x1FFFFFFFU; /* extended frame format (EFF) */


CanMsg(uint32_t const can_id, uint8_t const can_data_len, uint8_t const * can_data_ptr)
: id{can_id}
CanMsg(uint32_t const can_id, uint8_t const can_data_len, uint8_t const * can_data_ptr, bool const rtr = false)
: id{can_id | (rtr ? CAN_RTR_FLAG : 0)}
, data_length{min(can_data_len, MAX_DATA_LENGTH)}
, data{0}
{
Expand Down Expand Up @@ -87,14 +88,14 @@ class CanMsg : public Printable

virtual size_t printTo(Print & p) const override
{
char buf[20] = {0};
char buf[24] = {0};
size_t len = 0;

/* Print the header. */
if (isStandardId())
len = snprintf(buf, sizeof(buf), "[%03" PRIX32 "] (%d) : ", getStandardId(), data_length);
len = snprintf(buf, sizeof(buf), "[%03" PRIX32 "%s] (%d) : ", getStandardId(), isRtr() ? " RTR" : "", data_length);
else
len = snprintf(buf, sizeof(buf), "[%08" PRIX32 "] (%d) : ", getExtendedId(), data_length);
len = snprintf(buf, sizeof(buf), "[%08" PRIX32 "%s] (%d) : ", getExtendedId(), isRtr() ? " RTR" : "", data_length);
size_t n = p.write(buf, len);

/* Print the data. */
Expand All @@ -121,12 +122,18 @@ class CanMsg : public Printable
bool isExtendedId() const {
return ((id & CAN_EFF_FLAG) == CAN_EFF_FLAG);
}
bool isRtr() const {
return ((id & CAN_RTR_FLAG) == CAN_RTR_FLAG);
}
bool isRemote() const {
return isRtr();
}


/*
* CAN ID semantics (mirroring definition by linux/can.h):
* |- Bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
* |- Bit 30 : reserved (future remote transmission request flag)
* |- Bit 30 : remote transmission request flag (1 = RTR frame)
* |- Bit 29 : reserved (future error frame flag)
* |- Bit 0-28 : CAN identifier (11/29 bit)
*/
Expand All @@ -147,6 +154,14 @@ inline uint32_t CanExtendedId(uint32_t const id) {
return (CanMsg::CAN_EFF_FLAG | (id & CanMsg::CAN_EFF_MASK));
}

inline uint32_t CanStandardRtrId(uint32_t const id) {
return (CanMsg::CAN_RTR_FLAG | (id & CanMsg::CAN_SFF_MASK));
}

inline uint32_t CanExtendedRtrId(uint32_t const id) {
return (CanMsg::CAN_EFF_FLAG | CanMsg::CAN_RTR_FLAG | (id & CanMsg::CAN_EFF_MASK));
}

/**************************************************************************************
* NAMESPACE
**************************************************************************************/
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set(TEST_SRCS
src/CanMsg/test_CanStandardId.cpp
src/CanMsg/test_isExtendedId.cpp
src/CanMsg/test_isStandardId.cpp
src/CanMsg/test_isRtr.cpp
src/CanMsg/test_operator_assignment.cpp
src/CanMsg/test_printTo.cpp
src/CanMsgRingbuffer/test_available.cpp
Expand Down
59 changes: 59 additions & 0 deletions test/src/CanMsg/test_isRtr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2026 Arduino. All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

/**************************************************************************************
* INCLUDE
**************************************************************************************/

#include <catch2/catch_test_macros.hpp>

#include <api/CanMsg.h>

/**************************************************************************************
* NAMESPACE
**************************************************************************************/

using namespace arduino;

/**************************************************************************************
* TEST CODE
**************************************************************************************/

TEST_CASE ("\"isRtr\" should return true for standard RTR CAN ID", "[CanMsg-isRtr-01]")
{
CanMsg const msg_std_rtr(CanStandardRtrId(0x020), 0, nullptr);
REQUIRE(msg_std_rtr.isRtr() == true);
REQUIRE(msg_std_rtr.isRemote() == true);
REQUIRE(msg_std_rtr.isStandardId() == true);
REQUIRE(msg_std_rtr.isExtendedId() == false);
}

TEST_CASE ("\"isRtr\" should return true for extended RTR CAN ID", "[CanMsg-isRtr-02]")
{
CanMsg const msg_ext_rtr(CanExtendedRtrId(0x020), 0, nullptr);
REQUIRE(msg_ext_rtr.isRtr() == true);
REQUIRE(msg_ext_rtr.isRemote() == true);
REQUIRE(msg_ext_rtr.isStandardId() == false);
REQUIRE(msg_ext_rtr.isExtendedId() == true);
}

TEST_CASE ("\"isRtr\" should return true when created with rtr constructor flag", "[CanMsg-isRtr-03]")
{
CanMsg const msg_std_rtr_flag(CanStandardId(0x020), 0, nullptr, true);
REQUIRE(msg_std_rtr_flag.isRtr() == true);
REQUIRE(msg_std_rtr_flag.isRemote() == true);
}

TEST_CASE ("\"isRtr\" should return false for normal data frames", "[CanMsg-isRtr-04]")
{
CanMsg const msg_std(CanStandardId(0x020), 0, nullptr);
REQUIRE(msg_std.isRtr() == false);
REQUIRE(msg_std.isRemote() == false);

CanMsg const msg_ext(CanExtendedId(0x020), 0, nullptr);
REQUIRE(msg_ext.isRtr() == false);
REQUIRE(msg_ext.isRemote() == false);
}
20 changes: 20 additions & 0 deletions test/src/CanMsg/test_printTo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,23 @@ TEST_CASE ("Print CAN frame with extended ID", "[CanMsg-printTo-2]")

REQUIRE(mock._str == "[00000020] (4) : DEADC0DE");
}

TEST_CASE ("Print CAN frame with standard RTR ID", "[CanMsg-printTo-3]")
{
CanMsg const std_rtr_msg(CanStandardRtrId(0x20), 0, nullptr);

PrintMock mock;
mock.print(std_rtr_msg);

REQUIRE(mock._str == "[020 RTR] (0) : ");
}

TEST_CASE ("Print CAN frame with extended RTR ID", "[CanMsg-printTo-4]")
{
CanMsg const ext_rtr_msg(CanExtendedRtrId(0x20), 0, nullptr);

PrintMock mock;
mock.print(ext_rtr_msg);

REQUIRE(mock._str == "[00000020 RTR] (0) : ");
}
Loading