Skip to content

Commit fbc0646

Browse files
authored
Merge pull request #194 from arduino/fix-11-bit-can-id
Extend CanMsg to allow to distinguish between standard and extended ids …
2 parents 68d3e0d + 3733659 commit fbc0646

12 files changed

+435
-12
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.vscode/
2+
.idea/

api/CanMsg.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* This file is free software; you can redistribute it and/or modify
3+
* it under the terms of either the GNU General Public License version 2
4+
* or the GNU Lesser General Public License version 2.1, both as
5+
* published by the Free Software Foundation.
6+
*/
7+
8+
/**************************************************************************************
9+
* INCLUDE
10+
**************************************************************************************/
11+
12+
#include "CanMsg.h"
13+
14+
/**************************************************************************************
15+
* NAMESPACE
16+
**************************************************************************************/
17+
18+
namespace arduino
19+
{
20+
21+
/**************************************************************************************
22+
* STATIC CONST DEFINITION
23+
**************************************************************************************/
24+
25+
uint8_t const CanMsg::MAX_DATA_LENGTH;
26+
uint32_t const CanMsg::CAN_EFF_FLAG;
27+
uint32_t const CanMsg::CAN_SFF_MASK;
28+
uint32_t const CanMsg::CAN_EFF_MASK;
29+
30+
/**************************************************************************************
31+
* NAMESPACE
32+
**************************************************************************************/
33+
34+
} /* arduino */

api/CanMsg.h

+57-12
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#include <inttypes.h>
1616
#include <string.h>
1717

18-
#include <Arduino.h>
18+
#include "Print.h"
19+
#include "Printable.h"
20+
#include "Common.h"
1921

2022
/**************************************************************************************
2123
* NAMESPACE
@@ -31,14 +33,19 @@ namespace arduino
3133
class CanMsg : public Printable
3234
{
3335
public:
34-
static size_t constexpr MAX_DATA_LENGTH = 8;
36+
static uint8_t constexpr MAX_DATA_LENGTH = 8;
37+
38+
static uint32_t constexpr CAN_EFF_FLAG = 0x80000000U;
39+
static uint32_t constexpr CAN_SFF_MASK = 0x000007FFU; /* standard frame format (SFF) */
40+
static uint32_t constexpr CAN_EFF_MASK = 0x1FFFFFFFU; /* extended frame format (EFF) */
41+
3542

3643
CanMsg(uint32_t const can_id, uint8_t const can_data_len, uint8_t const * can_data_ptr)
3744
: id{can_id}
38-
, data_length{can_data_len}
45+
, data_length{min(can_data_len, MAX_DATA_LENGTH)}
3946
, data{0}
4047
{
41-
memcpy(data, can_data_ptr, min(can_data_len, MAX_DATA_LENGTH));
48+
memcpy(data, can_data_ptr, data_length);
4249
}
4350

4451
CanMsg() : CanMsg(0, 0, nullptr) { }
@@ -52,14 +59,15 @@ class CanMsg : public Printable
5259

5360
virtual ~CanMsg() { }
5461

55-
void operator = (CanMsg const & other)
62+
CanMsg & operator = (CanMsg const & other)
5663
{
57-
if (this == &other)
58-
return;
59-
60-
this->id = other.id;
61-
this->data_length = other.data_length;
62-
memcpy(this->data, other.data, this->data_length);
64+
if (this != &other)
65+
{
66+
this->id = other.id;
67+
this->data_length = other.data_length;
68+
memcpy(this->data, other.data, this->data_length);
69+
}
70+
return (*this);
6371
}
6472

6573
virtual size_t printTo(Print & p) const override
@@ -68,7 +76,10 @@ class CanMsg : public Printable
6876
size_t len = 0;
6977

7078
/* Print the header. */
71-
len = snprintf(buf, sizeof(buf), "[%08" PRIX32 "] (%d) : ", id, data_length);
79+
if (isStandardId())
80+
len = snprintf(buf, sizeof(buf), "[%03" PRIX32 "] (%d) : ", getStandardId(), data_length);
81+
else
82+
len = snprintf(buf, sizeof(buf), "[%08" PRIX32 "] (%d) : ", getExtendedId(), data_length);
7283
size_t n = p.write(buf, len);
7384

7485
/* Print the data. */
@@ -82,11 +93,45 @@ class CanMsg : public Printable
8293
return n;
8394
}
8495

96+
97+
uint32_t getStandardId() const {
98+
return (id & CAN_SFF_MASK);
99+
}
100+
uint32_t getExtendedId() const {
101+
return (id & CAN_EFF_MASK);
102+
}
103+
bool isStandardId() const {
104+
return ((id & CAN_EFF_FLAG) == 0);
105+
}
106+
bool isExtendedId() const {
107+
return ((id & CAN_EFF_FLAG) == CAN_EFF_FLAG);
108+
}
109+
110+
111+
/*
112+
* CAN ID semantics (mirroring definition by linux/can.h):
113+
* |- Bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
114+
* |- Bit 30 : reserved (future remote transmission request flag)
115+
* |- Bit 29 : reserved (future error frame flag)
116+
* |- Bit 0-28 : CAN identifier (11/29 bit)
117+
*/
85118
uint32_t id;
86119
uint8_t data_length;
87120
uint8_t data[MAX_DATA_LENGTH];
88121
};
89122

123+
/**************************************************************************************
124+
* FREE FUNCTIONS
125+
**************************************************************************************/
126+
127+
inline uint32_t CanStandardId(uint32_t const id) {
128+
return (id & CanMsg::CAN_SFF_MASK);
129+
}
130+
131+
inline uint32_t CanExtendedId(uint32_t const id) {
132+
return (CanMsg::CAN_EFF_FLAG | (id & CanMsg::CAN_EFF_MASK));
133+
}
134+
90135
/**************************************************************************************
91136
* NAMESPACE
92137
**************************************************************************************/

test/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ set(TEST_TARGET ${CMAKE_PROJECT_NAME})
2525
##########################################################################
2626

2727
set(TEST_SRCS
28+
src/CanMsg/test_CanMsg.cpp
29+
src/CanMsg/test_CanMsg_CopyCtor.cpp
30+
src/CanMsg/test_CanExtendedId.cpp
31+
src/CanMsg/test_CanStandardId.cpp
32+
src/CanMsg/test_isExtendedId.cpp
33+
src/CanMsg/test_isStandardId.cpp
34+
src/CanMsg/test_operator_assignment.cpp
35+
src/CanMsg/test_printTo.cpp
2836
src/Common/test_makeWord.cpp
2937
src/Common/test_map.cpp
3038
src/Common/test_max.cpp
@@ -95,6 +103,7 @@ set(TEST_SRCS
95103
)
96104

97105
set(TEST_DUT_SRCS
106+
../api/CanMsg.cpp
98107
../api/Common.cpp
99108
../api/IPAddress.cpp
100109
../api/String.cpp
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
* INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <CanMsg.h>
12+
13+
/**************************************************************************************
14+
* NAMESPACE
15+
**************************************************************************************/
16+
17+
using namespace arduino;
18+
19+
/**************************************************************************************
20+
* TEST CODE
21+
**************************************************************************************/
22+
23+
TEST_CASE ("Verify correct conversion to 29-Bit CAN ID for lowest valid 29-Bit CAN ID", "[CanMsg-CanExtendedId-01]")
24+
{
25+
REQUIRE(CanExtendedId(0) == (CanMsg::CAN_EFF_FLAG | 0U));
26+
}
27+
28+
TEST_CASE ("Verify correct conversion to 29-Bit CAN ID for highest valid 29-Bit CAN ID", "[CanMsg-CanExtendedId-02]")
29+
{
30+
REQUIRE(CanExtendedId(0x1FFFFFFFU) == (CanMsg::CAN_EFF_FLAG | 0x1FFFFFFFU));
31+
}
32+
33+
TEST_CASE ("Verify capping of CAN IDs exceeding 29-Bit CAN ID range", "[CanMsg-CanExtendedId-03]")
34+
{
35+
REQUIRE(CanExtendedId(0x2FFFFFFFU) == (CanMsg::CAN_EFF_FLAG | 0x0FFFFFFFU));
36+
REQUIRE(CanExtendedId(0x3FFFFFFFU) == (CanMsg::CAN_EFF_FLAG | 0x1FFFFFFFU));
37+
REQUIRE(CanExtendedId(0x4FFFFFFFU) == (CanMsg::CAN_EFF_FLAG | 0x0FFFFFFFU));
38+
REQUIRE(CanExtendedId(0x5FFFFFFFU) == (CanMsg::CAN_EFF_FLAG | 0x1FFFFFFFU));
39+
/* ... */
40+
REQUIRE(CanExtendedId(0xFFFFFFFFU) == (CanMsg::CAN_EFF_FLAG | 0x1FFFFFFFU));
41+
}

test/src/CanMsg/test_CanMsg.cpp

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
* INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <CanMsg.h>
12+
13+
/**************************************************************************************
14+
* NAMESPACE
15+
**************************************************************************************/
16+
17+
using namespace arduino;
18+
19+
/**************************************************************************************
20+
* TEST CODE
21+
**************************************************************************************/
22+
23+
TEST_CASE ("Test constructor with no data (data length = 0)", "[CanMsg-CanMsg-01]")
24+
{
25+
CanMsg const msg(CanStandardId(0x20), 0, nullptr);
26+
27+
REQUIRE(msg.data_length == 0);
28+
for (size_t i = 0; i < CanMsg::MAX_DATA_LENGTH; i++)
29+
REQUIRE(msg.data[i] == 0);
30+
}
31+
32+
TEST_CASE ("Test constructor with data (data length < CanMsg::MAX_DATA_LENGTH)", "[CanMsg-CanMsg-02]")
33+
{
34+
uint8_t const msg_data[4] = {0xDE, 0xAD, 0xC0, 0xDE};
35+
36+
CanMsg const msg(CanStandardId(0x20), sizeof(msg_data), msg_data);
37+
38+
REQUIRE(msg.data_length == 4);
39+
for (size_t i = 0; i < msg.data_length; i++)
40+
REQUIRE(msg.data[i] == msg_data[i]);
41+
}
42+
43+
TEST_CASE ("Test constructor with data (data length > CanMsg::MAX_DATA_LENGTH)", "[CanMsg-CanMsg-03]")
44+
{
45+
uint8_t const msg_data[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
46+
47+
CanMsg const msg(CanStandardId(0x20), sizeof(msg_data), msg_data);
48+
49+
REQUIRE(msg.data_length == 8);
50+
for (size_t i = 0; i < msg.data_length; i++)
51+
REQUIRE(msg.data[i] == msg_data[i]);
52+
}
53+
54+
TEST_CASE ("Test constructor constructing a CAN frame with standard ID", "[CanMsg-CanMsg-04]")
55+
{
56+
CanMsg const msg(CanStandardId(0x20), 0, nullptr);
57+
58+
REQUIRE(msg.id == 0x20);
59+
}
60+
61+
TEST_CASE ("Test constructor constructing a CAN frame with extended ID", "[CanMsg-CanMsg-05]")
62+
{
63+
CanMsg const msg(CanExtendedId(0x20), 0, nullptr);
64+
65+
REQUIRE(msg.id == (CanMsg::CAN_EFF_FLAG | 0x20));
66+
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
* INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <CanMsg.h>
12+
13+
/**************************************************************************************
14+
* NAMESPACE
15+
**************************************************************************************/
16+
17+
using namespace arduino;
18+
19+
/**************************************************************************************
20+
* TEST CODE
21+
**************************************************************************************/
22+
23+
TEST_CASE ("Test copy constructor", "[CanMsg-CopyCtor-01]")
24+
{
25+
uint8_t const msg_data[4] = {0xDE, 0xAD, 0xC0, 0xDE};
26+
27+
CanMsg const msg_1(CanStandardId(0x20), sizeof(msg_data), msg_data);
28+
CanMsg const msg_2(msg_1);
29+
30+
REQUIRE(msg_1.data_length == msg_2.data_length);
31+
32+
for (size_t i = 0; i < msg_1.data_length; i++)
33+
{
34+
REQUIRE(msg_1.data[i] == msg_data[i]);
35+
REQUIRE(msg_2.data[i] == msg_data[i]);
36+
}
37+
}
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
* INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <CanMsg.h>
12+
13+
/**************************************************************************************
14+
* NAMESPACE
15+
**************************************************************************************/
16+
17+
using namespace arduino;
18+
19+
/**************************************************************************************
20+
* TEST CODE
21+
**************************************************************************************/
22+
23+
TEST_CASE ("Verify correct conversion to 11-Bit CAN ID for lowest valid 11-Bit CAN ID", "[CanMsg-CanStandardId-01]")
24+
{
25+
REQUIRE(CanStandardId(0) == 0U);
26+
}
27+
28+
TEST_CASE ("Verify correct conversion to 11-Bit CAN ID for highest valid 11-Bit CAN ID", "[CanMsg-CanStandardId-02]")
29+
{
30+
REQUIRE(CanStandardId(0x7FF) == 0x7FF);
31+
}
32+
33+
TEST_CASE ("Verify capping of CAN IDs exceeding 11-Bit CAN ID range", "[CanMsg-CanStandardId-03]")
34+
{
35+
REQUIRE(CanStandardId(0x800U) == 0x000U);
36+
REQUIRE(CanStandardId(0x801U) == 0x001U);
37+
REQUIRE(CanStandardId(0x8FFU) == 0x0FFU);
38+
REQUIRE(CanStandardId(0x1FFFFFFFU) == 0x7FFU);
39+
REQUIRE(CanStandardId(0xFFFFFFFFU) == 0x7FFU);
40+
}

test/src/CanMsg/test_isExtendedId.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2020 Arduino. All rights reserved.
3+
*/
4+
5+
/**************************************************************************************
6+
* INCLUDE
7+
**************************************************************************************/
8+
9+
#include <catch.hpp>
10+
11+
#include <CanMsg.h>
12+
13+
/**************************************************************************************
14+
* NAMESPACE
15+
**************************************************************************************/
16+
17+
using namespace arduino;
18+
19+
/**************************************************************************************
20+
* TEST CODE
21+
**************************************************************************************/
22+
23+
TEST_CASE ("\"isExtendedId\" should return true for extended CAN ID", "[CanMsg-isExtendedId-01]")
24+
{
25+
CanMsg const msg_ext_id(CanExtendedId(0x020), 0, nullptr);
26+
REQUIRE(msg_ext_id.isExtendedId() == true);
27+
}
28+
29+
TEST_CASE ("\"isExtendedId\" should return false for standard CAN ID", "[CanMsg-isExtendedId-02]")
30+
{
31+
CanMsg const msg_std_id(CanStandardId(0x020), 0, nullptr);
32+
REQUIRE(msg_std_id.isExtendedId() == false);
33+
}

0 commit comments

Comments
 (0)