test: drivers: can: canfd: clean up and document the CAN-FD test cases

Clean up (naming, formatting) the CAN-FD test cases and add proper
doxygen documentation.

Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
Henrik Brix Andersen 2022-04-04 14:30:03 +02:00 committed by Carles Cufí
commit b5dfa3d777

View file

@ -1,56 +1,68 @@
/* /*
* Copyright (c) 2022 Vestas Wind Systems A/S
* Copyright (c) 2019 Alexander Wachter * Copyright (c) 2019 Alexander Wachter
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <drivers/can.h> #include <drivers/can.h>
#include <ztest.h> #include <ztest.h>
#include <strings.h>
/* /**
* @addtogroup t_can_driver * @addtogroup t_can_driver
* @{ * @{
* @defgroup t_canfd test_canfd * @defgroup t_can_canfd test_can_canfd
* @brief TestPurpose: Test CAN-FD
* @details
* - Test Steps
* -# Set driver to loopback mode
* -# Send and receive a message
* -# Send and receive a message with fd
* - Expected Results
* -# All tests MUST pass
* @} * @}
*/ */
/**
* @brief Test timeouts.
*/
#define TEST_SEND_TIMEOUT K_MSEC(100) #define TEST_SEND_TIMEOUT K_MSEC(100)
#define TEST_RECEIVE_TIMEOUT K_MSEC(100) #define TEST_RECEIVE_TIMEOUT K_MSEC(100)
/**
* @brief Standard (11-bit) CAN IDs used for testing.
*/
#define TEST_CAN_STD_ID_1 0x555 #define TEST_CAN_STD_ID_1 0x555
#define TEST_CAN_STD_ID_2 0x556 #define TEST_CAN_STD_ID_2 0x556
CAN_MSGQ_DEFINE(can_msgq, 5); /**
struct k_sem rx_isr_sem; * @brief Global variables.
struct k_sem rx_cb_sem; */
struct k_sem tx_cb_sem;
const struct device *can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus)); const struct device *can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
struct k_sem rx_callback_sem;
struct k_sem tx_callback_sem;
const struct zcan_frame test_std_msg_1 = { CAN_MSGQ_DEFINE(can_msgq, 5);
/**
* @brief Standard (11-bit) CAN ID frame 1.
*/
const struct zcan_frame test_std_frame_1 = {
.id_type = CAN_STANDARD_IDENTIFIER, .id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME, .rtr = CAN_DATAFRAME,
.id = TEST_CAN_STD_ID_1, .id = TEST_CAN_STD_ID_1,
.dlc = 8, .dlc = 8,
.data = {1, 2, 3, 4, 5, 6, 7, 8} .data = { 1, 2, 3, 4, 5, 6, 7, 8 }
}; };
const struct zcan_frame test_std_msg_2 = { /**
* @brief Standard (11-bit) CAN ID frame 2.
*/
const struct zcan_frame test_std_frame_2 = {
.id_type = CAN_STANDARD_IDENTIFIER, .id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME, .rtr = CAN_DATAFRAME,
.id = TEST_CAN_STD_ID_2, .id = TEST_CAN_STD_ID_2,
.dlc = 8, .dlc = 8,
.data = {1, 2, 3, 4, 5, 6, 7, 8} .data = { 1, 2, 3, 4, 5, 6, 7, 8 }
}; };
const struct zcan_frame test_std_msg_fd_1 = { /**
* @brief Standard (11-bit) CAN ID frame 1 with CAN-FD payload.
*/
const struct zcan_frame test_std_frame_fd_1 = {
.id = TEST_CAN_STD_ID_1, .id = TEST_CAN_STD_ID_1,
.fd = 1, .fd = 1,
.rtr = CAN_DATAFRAME, .rtr = CAN_DATAFRAME,
@ -61,10 +73,13 @@ const struct zcan_frame test_std_msg_fd_1 = {
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, 62, 63, 64} 61, 62, 63, 64 }
}; };
const struct zcan_frame test_std_msg_fd_2 = { /**
* @brief Standard (11-bit) CAN ID frame 1 with CAN-FD payload.
*/
const struct zcan_frame test_std_frame_fd_2 = {
.id = TEST_CAN_STD_ID_2, .id = TEST_CAN_STD_ID_2,
.fd = 1, .fd = 1,
.rtr = CAN_DATAFRAME, .rtr = CAN_DATAFRAME,
@ -75,9 +90,12 @@ const struct zcan_frame test_std_msg_fd_2 = {
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, 62, 63, 64} 61, 62, 63, 64 }
}; };
/**
* @brief Standard (11-bit) CAN ID filter 1.
*/
const struct zcan_filter test_std_filter_1 = { const struct zcan_filter test_std_filter_1 = {
.id_type = CAN_STANDARD_IDENTIFIER, .id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME, .rtr = CAN_DATAFRAME,
@ -86,6 +104,9 @@ const struct zcan_filter test_std_filter_1 = {
.id_mask = CAN_STD_ID_MASK .id_mask = CAN_STD_ID_MASK
}; };
/**
* @brief Standard (11-bit) CAN ID filter 2.
*/
const struct zcan_filter test_std_filter_2 = { const struct zcan_filter test_std_filter_2 = {
.id_type = CAN_STANDARD_IDENTIFIER, .id_type = CAN_STANDARD_IDENTIFIER,
.rtr = CAN_DATAFRAME, .rtr = CAN_DATAFRAME,
@ -94,233 +115,281 @@ const struct zcan_filter test_std_filter_2 = {
.id_mask = CAN_STD_ID_MASK .id_mask = CAN_STD_ID_MASK
}; };
static inline void check_msg(const struct zcan_frame *msg1, /**
const struct zcan_frame *msg2) * @brief Assert that two CAN frames are equal.
*
* @param frame1 First CAN frame.
* @param frame2 Second CAN frame.
*/
static inline void assert_frame_equal(const struct zcan_frame *frame1,
const struct zcan_frame *frame2)
{ {
int cmp_res; zassert_equal(frame1->id_type, frame2->id_type, "ID type does not match");
zassert_equal(frame1->rtr, frame2->rtr, "RTR bit does not match");
zassert_equal(msg1->id_type, msg2->id_type, "ID type does not match"); zassert_equal(frame1->id, frame2->id, "ID does not match");
zassert_equal(frame1->dlc, frame2->dlc, "DLC does not match");
zassert_equal(msg1->rtr, msg2->rtr, "RTR bit does not match"); zassert_mem_equal(frame1->data, frame2->data, frame1->dlc, "Received data differ");
zassert_equal(msg1->id, msg2->id, "ID does not match");
zassert_equal(msg1->dlc, msg2->dlc, "DLC does not match");
cmp_res = memcmp(msg1->data, msg2->data, can_dlc_to_bytes(msg1->dlc));
zassert_equal(cmp_res, 0, "Received data differ");
} }
static void tx_std_isr_1(const struct device *dev, int error, void *arg) static void tx_std_callback_1(const struct device *dev, int error, void *user_data)
{ {
const struct zcan_frame *msg = (const struct zcan_frame *)arg; const struct zcan_frame *frame = user_data;
k_sem_give(&tx_cb_sem); k_sem_give(&tx_callback_sem);
zassert_equal(dev, can_dev, "CAN device does not match"); zassert_equal(dev, can_dev, "CAN device does not match");
zassert_equal(msg->id, TEST_CAN_STD_ID_1, "Arg does not match"); zassert_equal(frame->id, TEST_CAN_STD_ID_1, "ID does not match");
} }
static void tx_std_isr_2(const struct device *dev, int error, void *arg) static void tx_std_callback_2(const struct device *dev, int error, void *user_data)
{ {
const struct zcan_frame *msg = (const struct zcan_frame *)arg; const struct zcan_frame *frame = user_data;
k_sem_give(&tx_cb_sem); k_sem_give(&tx_callback_sem);
zassert_equal(dev, can_dev, "CAN device does not match"); zassert_equal(dev, can_dev, "CAN device does not match");
zassert_equal(msg->id, TEST_CAN_STD_ID_2, "Arg does not match"); zassert_equal(frame->id, TEST_CAN_STD_ID_2, "ID does not match");
} }
static void rx_std_isr_1(const struct device *dev, struct zcan_frame *msg, void *arg) static void rx_std_callback_1(const struct device *dev, struct zcan_frame *frame, void *user_data)
{ {
check_msg(msg, &test_std_msg_1); struct zcan_filter *filter = user_data;
assert_frame_equal(frame, &test_std_frame_1);
zassert_equal(dev, can_dev, "CAN device does not match"); zassert_equal(dev, can_dev, "CAN device does not match");
zassert_equal_ptr(arg, &test_std_filter_1, "arg does not match"); zassert_equal_ptr(filter, &test_std_filter_1, "filter does not match");
k_sem_give(&rx_isr_sem);
k_sem_give(&rx_callback_sem);
} }
static void rx_std_isr_2(const struct device *dev, struct zcan_frame *msg, void *arg) static void rx_std_callback_2(const struct device *dev, struct zcan_frame *frame, void *user_data)
{ {
check_msg(msg, &test_std_msg_2); struct zcan_filter *filter = user_data;
assert_frame_equal(frame, &test_std_frame_2);
zassert_equal(dev, can_dev, "CAN device does not match"); zassert_equal(dev, can_dev, "CAN device does not match");
zassert_equal_ptr(arg, &test_std_filter_2, "arg does not match"); zassert_equal_ptr(filter, &test_std_filter_2, "filter does not match");
k_sem_give(&rx_isr_sem);
k_sem_give(&rx_callback_sem);
} }
static void rx_std_isr_fd_1(const struct device *dev, struct zcan_frame *msg, void *arg) static void rx_std_callback_fd_1(const struct device *dev, struct zcan_frame *frame,
void *user_data)
{ {
check_msg(msg, &test_std_msg_fd_1); struct zcan_filter *filter = user_data;
assert_frame_equal(frame, &test_std_frame_fd_1);
zassert_equal(dev, can_dev, "CAN device does not match"); zassert_equal(dev, can_dev, "CAN device does not match");
zassert_equal_ptr(arg, &test_std_filter_1, "arg does not match"); zassert_equal_ptr(filter, &test_std_filter_1, "filter does not match");
k_sem_give(&rx_isr_sem);
k_sem_give(&rx_callback_sem);
} }
static void rx_std_isr_fd_2(const struct device *dev, struct zcan_frame *msg, void *arg) static void rx_std_callback_fd_2(const struct device *dev, struct zcan_frame *frame,
void *user_data)
{ {
check_msg(msg, &test_std_msg_fd_2); struct zcan_filter *filter = user_data;
assert_frame_equal(frame, &test_std_frame_fd_2);
zassert_equal(dev, can_dev, "CAN device does not match"); zassert_equal(dev, can_dev, "CAN device does not match");
zassert_equal_ptr(arg, &test_std_filter_2, "arg does not match"); zassert_equal_ptr(filter, &test_std_filter_2, "filter does not match");
k_sem_give(&rx_isr_sem);
k_sem_give(&rx_callback_sem);
} }
static void send_test_msg(const struct device *can_dev, /**
const struct zcan_frame *msg) * @brief Send a CAN test frame with asserts.
*
* This function will block until the frame is transmitted or a test timeout
* occurs.
*
* @param dev Pointer to the device structure for the driver instance.
* @param frame Pointer to the CAN frame to send.
*/
static void send_test_frame(const struct device *dev, const struct zcan_frame *frame)
{ {
int ret; int err;
ret = can_send(can_dev, msg, TEST_SEND_TIMEOUT, NULL, NULL); err = can_send(dev, frame, TEST_SEND_TIMEOUT, NULL, NULL);
zassert_not_equal(ret, -EBUSY, zassert_not_equal(err, -EBUSY, "arbitration lost in loopback mode");
"Arbitration though in loopback mode"); zassert_equal(err, 0, "failed to send frame (err %d)", err);
zassert_equal(ret, 0, "Can't send a message. Err: %d", ret);
} }
static void send_test_msg_nowait(const struct device *can_dev, /**
const struct zcan_frame *msg, * @brief Send a CAN test frame with asserts.
can_tx_callback_t cb) *
* This function will block until the frame is queued or a test timeout
* occurs.
*
* @param dev Pointer to the device structure for the driver instance.
* @param frame Pointer to the CAN frame to send.
* @param callback Transmit callback function.
*/
static void send_test_frame_nowait(const struct device *dev, const struct zcan_frame *frame,
can_tx_callback_t callback)
{ {
int ret; int err;
ret = can_send(can_dev, msg, TEST_SEND_TIMEOUT, cb, err = can_send(dev, frame, TEST_SEND_TIMEOUT, callback, (void *)frame);
(struct zcan_frame *)msg); zassert_not_equal(err, -EBUSY, "arbitration lost in loopback mode");
zassert_not_equal(ret, -EBUSY, zassert_equal(err, 0, "failed to send frame (err %d)", err);
"Arbitration though in loopback mode");
zassert_equal(ret, 0, "Can't send a message. Err: %d", ret);
} }
static inline int add_rx_msgq(const struct device *can_dev, /**
const struct zcan_filter *filter) * @brief Add a CAN message queue with asserts.
*
* @param dev Pointer to the device structure for the driver instance.
* @param filter CAN filter for the CAN message queue.
*
* @return CAN filter ID.
*/
static inline int add_rx_msgq(const struct device *dev, const struct zcan_filter *filter)
{ {
int filter_id; int filter_id;
filter_id = can_add_rx_filter_msgq(can_dev, &can_msgq, filter); filter_id = can_add_rx_filter_msgq(dev, &can_msgq, filter);
zassert_not_equal(filter_id, -ENOSPC, zassert_not_equal(filter_id, -ENOSPC, "no filters available");
"Filter full even for a single one"); zassert_true(filter_id >= 0, "negative filter number");
zassert_true((filter_id >= 0), "Negative filter number");
return filter_id; return filter_id;
} }
static inline int add_rx_filter(const struct device *can_dev, /**
* @brief Add a CAN filter with asserts.
*
* @param dev Pointer to the device structure for the driver instance.
* @param filter CAN filter.
* @param callback Receive callback function.
*
* @return CAN filter ID.
*/
static inline int add_rx_filter(const struct device *dev,
const struct zcan_filter *filter, const struct zcan_filter *filter,
can_rx_callback_t callback) can_rx_callback_t callback)
{ {
int filter_id; int filter_id;
k_sem_reset(&rx_isr_sem); k_sem_reset(&rx_callback_sem);
filter_id = can_add_rx_filter(can_dev, callback, (void *)filter, filter); filter_id = can_add_rx_filter(dev, callback, (void *)filter, filter);
zassert_not_equal(filter_id, -ENOSPC, zassert_not_equal(filter_id, -ENOSPC, "no filters available");
"Filter full even for a single one"); zassert_true(filter_id >= 0, "negative filter number");
zassert_true((filter_id >= 0), "Negative filter number");
return filter_id; return filter_id;
} }
/**
* @brief Perform a send/receive test with a set of CAN ID filters and CAN frames.
*
* @param filter1 CAN filter 1
* @param filter2 CAN filter 2
* @param frame1 CAN frame 1
* @param frame2 CAN frame 2
*/
static void send_receive(const struct zcan_filter *filter1, static void send_receive(const struct zcan_filter *filter1,
const struct zcan_filter *filter2, const struct zcan_filter *filter2,
const struct zcan_frame *msg1, const struct zcan_frame *frame1,
const struct zcan_frame *msg2) const struct zcan_frame *frame2)
{ {
int ret, filter_id_1, filter_id_2; struct zcan_frame frame_buffer;
struct zcan_frame msg_buffer; int filter_id_1;
int filter_id_2;
zassert_not_null(can_dev, "Device not not found"); int err;
filter_id_1 = add_rx_msgq(can_dev, filter1); filter_id_1 = add_rx_msgq(can_dev, filter1);
send_test_msg(can_dev, msg1); send_test_frame(can_dev, frame1);
ret = k_msgq_get(&can_msgq, &msg_buffer, TEST_RECEIVE_TIMEOUT);
zassert_equal(ret, 0, "Receiving timeout");
check_msg(&msg_buffer, msg1); err = k_msgq_get(&can_msgq, &frame_buffer, TEST_RECEIVE_TIMEOUT);
zassert_equal(err, 0, "receive timeout");
assert_frame_equal(&frame_buffer, frame1);
can_remove_rx_filter(can_dev, filter_id_1); can_remove_rx_filter(can_dev, filter_id_1);
k_sem_reset(&tx_cb_sem); k_sem_reset(&tx_callback_sem);
if (msg1->fd) { if (frame1->fd) {
filter_id_1 = add_rx_filter(can_dev, filter1, rx_std_isr_fd_1); filter_id_1 = add_rx_filter(can_dev, filter1, rx_std_callback_fd_1);
} else { } else {
filter_id_1 = add_rx_filter(can_dev, filter1, rx_std_isr_1); filter_id_1 = add_rx_filter(can_dev, filter1, rx_std_callback_1);
} }
if (msg2->fd) { if (frame2->fd) {
filter_id_2 = add_rx_filter(can_dev, filter2, rx_std_isr_fd_2); filter_id_2 = add_rx_filter(can_dev, filter2, rx_std_callback_fd_2);
} else { } else {
filter_id_2 = add_rx_filter(can_dev, filter2, rx_std_isr_2); filter_id_2 = add_rx_filter(can_dev, filter2, rx_std_callback_2);
} }
send_test_msg_nowait(can_dev, msg1, tx_std_isr_1); send_test_frame_nowait(can_dev, frame1, tx_std_callback_1);
send_test_msg_nowait(can_dev, msg2, tx_std_isr_2); send_test_frame_nowait(can_dev, frame2, tx_std_callback_2);
err = k_sem_take(&rx_callback_sem, TEST_RECEIVE_TIMEOUT);
zassert_equal(err, 0, "receive timeout");
err = k_sem_take(&rx_callback_sem, TEST_RECEIVE_TIMEOUT);
zassert_equal(err, 0, "receive timeout");
err = k_sem_take(&tx_callback_sem, TEST_SEND_TIMEOUT);
zassert_equal(err, 0, "missing TX callback");
err = k_sem_take(&tx_callback_sem, TEST_SEND_TIMEOUT);
zassert_equal(err, 0, "missing TX callback");
ret = k_sem_take(&rx_isr_sem, TEST_RECEIVE_TIMEOUT);
zassert_equal(ret, 0, "Receiving timeout");
ret = k_sem_take(&rx_isr_sem, TEST_RECEIVE_TIMEOUT);
zassert_equal(ret, 0, "Receiving timeout");
ret = k_sem_take(&tx_cb_sem, TEST_SEND_TIMEOUT);
zassert_equal(ret, 0, "Missing TX callback");
ret = k_sem_take(&tx_cb_sem, TEST_SEND_TIMEOUT);
zassert_equal(ret, 0, "Missing TX callback");
can_remove_rx_filter(can_dev, filter_id_1); can_remove_rx_filter(can_dev, filter_id_1);
can_remove_rx_filter(can_dev, filter_id_2); can_remove_rx_filter(can_dev, filter_id_2);
} }
/* /**
* Set driver to loopback mode * @brief Test configuring the CAN controller for loopback mode.
* The driver stays in loopback mode after that. *
* The controller can now be tested against itself * This test case must be run before sending/receiving test cases as it allows
* these test cases to send/receive their own frames.
*/ */
static void test_set_loopback(void) static void test_set_loopback(void)
{ {
int ret; int err;
ret = can_set_mode(can_dev, CAN_LOOPBACK_MODE); err = can_set_mode(can_dev, CAN_LOOPBACK_MODE);
zassert_equal(ret, 0, "Can't set loopback-mode. Err: %d", ret); zassert_equal(err, 0, "failed to set loopback-mode (err %d)", err);
} }
/* /**
* Attach to a filter that should pass the message and send the message. * @brief Test send/receive with standard (11-bit) CAN IDs and classic CAN frames.
* The massage should be received within a small timeout.
* Standard identifier, classic frame
*/ */
void test_send_receive_std(void) void test_send_receive_classic(void)
{ {
send_receive(&test_std_filter_1, &test_std_filter_2, send_receive(&test_std_filter_1, &test_std_filter_2,
&test_std_msg_1, &test_std_msg_2); &test_std_frame_1, &test_std_frame_2);
} }
/* /**
* Attach to a filter that should pass the message and send the message. * @brief Test send/receive with standard (11-bit) CAN IDs and CAN-FD frames.
* The massage should be received within a small timeout.
* Standard identifier, fd frame
*/ */
void test_send_receive_fd(void) void test_send_receive_fd(void)
{ {
send_receive(&test_std_filter_1, &test_std_filter_2, send_receive(&test_std_filter_1, &test_std_filter_2,
&test_std_msg_fd_1, &test_std_msg_fd_2); &test_std_frame_fd_1, &test_std_frame_fd_2);
} }
/* /**
* Attach to a filter that should pass the message and send the message. * @brief Test send/receive with (11-bit) CAN IDs, mixed classic and CAN-FD frames.
* The massage should be received within a small timeout.
* Standard identifier, classic frame and fd
*/ */
void test_send_receive_mix(void) void test_send_receive_mixed(void)
{ {
send_receive(&test_std_filter_1, &test_std_filter_2, send_receive(&test_std_filter_1, &test_std_filter_2,
&test_std_msg_fd_1, &test_std_msg_2); &test_std_frame_fd_1, &test_std_frame_2);
} }
void test_main(void) void test_main(void)
{ {
k_sem_init(&rx_isr_sem, 0, 2); k_sem_init(&rx_callback_sem, 0, 2);
k_sem_init(&rx_cb_sem, 0, INT_MAX); k_sem_init(&tx_callback_sem, 0, 2);
k_sem_init(&tx_cb_sem, 0, 2);
zassert_true(device_is_ready(can_dev), "CAN device not ready"); zassert_true(device_is_ready(can_dev), "CAN device not ready");
ztest_test_suite(canfd_driver, ztest_test_suite(canfd_driver,
ztest_unit_test(test_set_loopback), ztest_unit_test(test_set_loopback),
ztest_unit_test(test_send_receive_std), ztest_unit_test(test_send_receive_classic),
ztest_unit_test(test_send_receive_fd), ztest_unit_test(test_send_receive_fd),
ztest_unit_test(test_send_receive_mix)); ztest_unit_test(test_send_receive_mixed));
ztest_run_test_suite(canfd_driver); ztest_run_test_suite(canfd_driver);
} }