A growing number of CAN controllers do not have support for individual RX hardware filters based on the Remote Transmission Request (RTR) bit. This leads to various work-arounds on the driver level mixing hardware and software filtering. As the use of RTR frames is discouraged by CAN in Automation (CiA) - and not even supported by newer standards, e.g. CAN FD - this often leads to unnecessary overhead, added complexity, and worst-case to non-portable behavior between various CAN controller drivers. Instead, move to a simpler approach where the ability to accept/reject RTR frames is globally configured via Kconfig. By default, all incoming RTR frames are rejected at the driver level, a setting which can be supported in hardware by most in-tree CAN controllers drivers. Legacy applications or protocol implementations, where RTR reception is required, can now select CONFIG_CAN_ACCEPT_RTR to accept incoming RTR frames matching added CAN filters. These applications or protocols will need to distinguish between RTR and data frames in their respective CAN RX frame handling routines. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
152 lines
4.7 KiB
C
152 lines
4.7 KiB
C
/*
|
|
* Copyright (c) 2022 Vestas Wind Systems A/S
|
|
* Copyright (c) 2019 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/net/socketcan.h>
|
|
#include <zephyr/net/socketcan_utils.h>
|
|
#include <zephyr/ztest.h>
|
|
|
|
LOG_MODULE_REGISTER(socket_can, LOG_LEVEL_ERR);
|
|
|
|
/**
|
|
* @brief Test of @a socketcan_to_can_frame()
|
|
*/
|
|
ZTEST(socket_can, test_socketcan_frame_to_can_frame)
|
|
{
|
|
struct socketcan_frame sframe = { 0 };
|
|
struct can_frame expected = { 0 };
|
|
struct can_frame zframe;
|
|
const uint8_t data[SOCKETCAN_MAX_DLEN] = { 0x01, 0x02, 0x03, 0x04,
|
|
0x05, 0x06, 0x07, 0x08 };
|
|
|
|
sframe.can_id = BIT(31) | 1234;
|
|
sframe.len = sizeof(data);
|
|
memcpy(sframe.data, data, sizeof(sframe.data));
|
|
|
|
expected.flags = CAN_FRAME_IDE;
|
|
expected.id = 1234U;
|
|
expected.dlc = can_bytes_to_dlc(sizeof(data));
|
|
memcpy(expected.data, data, sizeof(data));
|
|
|
|
socketcan_to_can_frame(&sframe, &zframe);
|
|
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&sframe, sizeof(sframe), "sframe");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&zframe, sizeof(zframe), "zframe");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&expected, sizeof(expected), "expected");
|
|
|
|
zassert_equal(zframe.flags, expected.flags, "Flags not equal");
|
|
zassert_equal(zframe.id, expected.id, "CAN id invalid");
|
|
zassert_equal(zframe.dlc, expected.dlc, "Msg length invalid");
|
|
zassert_mem_equal(&zframe.data, &expected.data, can_dlc_to_bytes(expected.dlc),
|
|
"CAN data not same");
|
|
|
|
/* Test RTR flag conversion after comparing data payload */
|
|
sframe.can_id |= BIT(30);
|
|
expected.flags |= CAN_FRAME_RTR;
|
|
|
|
socketcan_to_can_frame(&sframe, &zframe);
|
|
|
|
zassert_equal(zframe.flags, expected.flags, "Flags not equal");
|
|
zassert_equal(zframe.id, expected.id, "CAN id invalid");
|
|
}
|
|
|
|
/**
|
|
* @brief Test of @a socketcan_from_can_frame()
|
|
*/
|
|
ZTEST(socket_can, test_can_frame_to_socketcan_frame)
|
|
{
|
|
struct socketcan_frame sframe = { 0 };
|
|
struct socketcan_frame expected = { 0 };
|
|
struct can_frame zframe = { 0 };
|
|
const uint8_t data[SOCKETCAN_MAX_DLEN] = { 0x01, 0x02, 0x03, 0x04,
|
|
0x05, 0x06, 0x07, 0x08 };
|
|
|
|
expected.can_id = BIT(31) | 1234;
|
|
expected.len = sizeof(data);
|
|
memcpy(expected.data, data, sizeof(expected.data));
|
|
|
|
zframe.flags = CAN_FRAME_IDE;
|
|
zframe.id = 1234U;
|
|
zframe.dlc = can_bytes_to_dlc(sizeof(data));
|
|
memcpy(zframe.data, data, sizeof(data));
|
|
|
|
socketcan_from_can_frame(&zframe, &sframe);
|
|
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&sframe, sizeof(sframe), "sframe");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&zframe, sizeof(zframe), "zframe");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&expected, sizeof(expected), "expected");
|
|
|
|
zassert_equal(sframe.can_id, expected.can_id, "CAN ID not same");
|
|
zassert_equal(sframe.len, expected.len, "CAN msg length not same");
|
|
zassert_mem_equal(&sframe.data, &expected.data, sizeof(sframe.data), "CAN data not same");
|
|
|
|
/* Test RTR flag conversion after comparing data payload */
|
|
expected.can_id |= BIT(30);
|
|
zframe.flags |= CAN_FRAME_RTR;
|
|
|
|
socketcan_from_can_frame(&zframe, &sframe);
|
|
zassert_equal(sframe.can_id, expected.can_id, "CAN ID not same");
|
|
}
|
|
|
|
/**
|
|
* @brief Test of @a socketcan_to_can_filter()
|
|
*/
|
|
ZTEST(socket_can, test_socketcan_filter_to_can_filter)
|
|
{
|
|
struct socketcan_filter sfilter = { 0 };
|
|
struct can_filter expected = { 0 };
|
|
struct can_filter zfilter = { 0 };
|
|
|
|
sfilter.can_id = BIT(31) | 1234;
|
|
sfilter.can_mask = BIT(31) | 1234;
|
|
|
|
expected.flags = CAN_FILTER_IDE;
|
|
expected.id = 1234U;
|
|
expected.mask = 1234U;
|
|
|
|
socketcan_to_can_filter(&sfilter, &zfilter);
|
|
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&zfilter, sizeof(zfilter), "zfilter");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&sfilter, sizeof(sfilter), "sfilter");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&expected, sizeof(expected), "expected");
|
|
|
|
zassert_equal(zfilter.flags, expected.flags, "Flags not equal");
|
|
zassert_equal(zfilter.id, expected.id, "CAN id invalid");
|
|
zassert_equal(zfilter.mask, expected.mask, "id mask not set");
|
|
}
|
|
|
|
/**
|
|
* @brief Test of @a socketcan_from_can_filter()
|
|
*/
|
|
ZTEST(socket_can, test_can_filter_to_socketcan_filter)
|
|
{
|
|
struct socketcan_filter sfilter = { 0 };
|
|
struct socketcan_filter expected = { 0 };
|
|
struct can_filter zfilter = { 0 };
|
|
|
|
expected.can_id = BIT(31) | 1234;
|
|
expected.can_mask = BIT(31) | 1234;
|
|
#ifndef CONFIG_CAN_ACCEPT_RTR
|
|
expected.can_mask |= BIT(30);
|
|
#endif /* !CONFIG_CAN_ACCEPT_RTR */
|
|
|
|
zfilter.flags = CAN_FILTER_IDE;
|
|
zfilter.id = 1234U;
|
|
zfilter.mask = 1234U;
|
|
|
|
socketcan_from_can_filter(&zfilter, &sfilter);
|
|
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&zfilter, sizeof(zfilter), "zfilter");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&sfilter, sizeof(sfilter), "sfilter");
|
|
LOG_HEXDUMP_DBG((const uint8_t *)&expected, sizeof(expected), "expected");
|
|
|
|
zassert_equal(sfilter.can_id, expected.can_id, "CAN ID not same");
|
|
zassert_equal(sfilter.can_mask, expected.can_mask, "CAN mask not same");
|
|
}
|
|
|
|
ZTEST_SUITE(socket_can, NULL, NULL, NULL, NULL, NULL);
|