Skip to content

Commit 9bdd5e3

Browse files
committed
test(driver_twai): new driver add test case
1 parent 043c46b commit 9bdd5e3

File tree

8 files changed

+392
-0
lines changed

8 files changed

+392
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
components/esp_driver_twai/test_apps/twaifd_test:
2+
disable:
3+
- if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD != 1
4+
reason: Only support FD targets now
5+
depends_components:
6+
- esp_driver_twai
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This is the project CMakeLists.txt file for the test subproject
2+
cmake_minimum_required(VERSION 3.16)
3+
4+
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
5+
set(COMPONENTS main)
6+
7+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
8+
project(twaifd_test)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| Supported Targets | ESP32-C5 |
2+
| ----------------- | -------- |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
set(srcs
2+
"test_app_main.c"
3+
"test_twaifd.c"
4+
)
5+
6+
idf_component_register(
7+
SRCS ${srcs}
8+
PRIV_REQUIRES esp_driver_twai
9+
WHOLE_ARCHIVE
10+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dependencies:
2+
test_utils:
3+
path: ${IDF_PATH}/tools/unit-test-app/components/test_utils
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "unity_test_utils.h"
8+
#include "unity_test_runner.h"
9+
#include "unity_test_utils_memory.h"
10+
#include "esp_heap_caps.h"
11+
12+
#define LEAKS (200)
13+
14+
void setUp(void)
15+
{
16+
unity_utils_record_free_mem();
17+
}
18+
19+
void tearDown(void)
20+
{
21+
unity_utils_evaluate_leaks_direct(LEAKS);
22+
}
23+
24+
void app_main(void)
25+
{
26+
unity_run_menu();
27+
}
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <string.h>
8+
#include <sys/param.h>
9+
#include "unity.h"
10+
#include "esp_log.h"
11+
#include "esp_heap_caps.h"
12+
#include "freertos/FreeRTOS.h"
13+
#include "test_utils.h"
14+
#include "esp_twai.h"
15+
#include "esp_twai_onchip.h"
16+
17+
#define TEST_TX_GPIO 4
18+
#define TEST_RX_GPIO 5
19+
#define TEST_TWAI_QUEUE_DEPTH 5
20+
#define TEST_TRANS_LEN 100
21+
#define TEST_FRAME_LEN 7
22+
#define TEST_FRAME_NUM howmany(TEST_TRANS_LEN, TEST_FRAME_LEN)
23+
24+
static bool test_driver_install_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
25+
{
26+
twai_frame_header_t rx_header;
27+
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_header, NULL, 0, NULL)) {
28+
ESP_EARLY_LOGI("Recv ", "id 0x%lx rtr %d", rx_header.id, rx_header.rtr);
29+
}
30+
if (rx_header.id != 0x100) {
31+
TEST_FAIL(); //callback is unregistered, should not run here
32+
}
33+
return false;
34+
}
35+
36+
TEST_CASE("twai install uninstall (loopback)", "[TWAI]")
37+
{
38+
esp_err_t ret;
39+
twai_node_handle_t node_hdl[SOC_TWAI_CONTROLLER_NUM + 1];
40+
twai_onchip_node_config_t node_config = {
41+
.io_cfg.tx = TEST_TX_GPIO,
42+
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
43+
.bit_timing.bitrate = 1000000,
44+
.data_timing.bitrate = 1000000,
45+
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
46+
.flags.enable_loopback = true,
47+
.flags.enable_self_test = true,
48+
};
49+
50+
// loop 10 times to check memory leak
51+
for (uint8_t loop = 0; loop < 10; loop ++) {
52+
for (uint8_t i = 0; i < SOC_TWAI_CONTROLLER_NUM + 1; i++) {
53+
ret = twai_new_node_onchip(&node_config, &node_hdl[i]);
54+
printf("Install TWAI%d return %s\n", i, esp_err_to_name(ret));
55+
TEST_ASSERT(ret == ((i < SOC_TWAI_CONTROLLER_NUM) ? ESP_OK : ESP_ERR_NOT_FOUND));
56+
}
57+
// can't disable before enable
58+
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_disable(node_hdl[0]));
59+
twai_event_callbacks_t user_cbs = {
60+
.on_rx_done = test_driver_install_rx_cb,
61+
};
62+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL));
63+
64+
printf("Test unregister callback\n");
65+
user_cbs.on_rx_done = NULL;
66+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL));
67+
68+
twai_frame_t tx_frame = {
69+
.header.id = 0x82,
70+
.header.rtr = true,
71+
};
72+
printf("Test transmit before enable\n");
73+
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_transmit(node_hdl[0], &tx_frame, 0));
74+
TEST_ESP_OK(twai_node_enable(node_hdl[0]));
75+
TEST_ESP_OK(twai_node_disable(node_hdl[0]));
76+
TEST_ESP_OK(twai_node_enable(node_hdl[0]));
77+
TEST_ESP_OK(twai_node_transmit(node_hdl[0], &tx_frame, 0));
78+
79+
TEST_ESP_OK(twai_node_disable(node_hdl[0]));
80+
TEST_ESP_OK(twai_node_delete(node_hdl[0]));
81+
82+
printf("Test install after delete\n");
83+
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl[SOC_TWAI_CONTROLLER_NUM]));
84+
user_cbs.on_rx_done = test_driver_install_rx_cb,
85+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[SOC_TWAI_CONTROLLER_NUM], &user_cbs, NULL));
86+
TEST_ESP_OK(twai_node_enable(node_hdl[SOC_TWAI_CONTROLLER_NUM]));
87+
tx_frame.header.id = 0x100;
88+
TEST_ESP_OK(twai_node_transmit(node_hdl[SOC_TWAI_CONTROLLER_NUM], &tx_frame, 0));
89+
twai_frame_t rx_frame;
90+
printf("Test receive from task\n");
91+
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_receive_from_isr(node_hdl[SOC_TWAI_CONTROLLER_NUM], &rx_frame.header, rx_frame.buffer, rx_frame.buffer_len, NULL));
92+
93+
TEST_ESP_OK(twai_node_disable(node_hdl[SOC_TWAI_CONTROLLER_NUM]));
94+
for (uint8_t i = 1; i <= SOC_TWAI_CONTROLLER_NUM; i++) {
95+
printf("Uninstall TWAI%d\n", i - 1);
96+
TEST_ESP_OK(twai_node_delete(node_hdl[i]));
97+
}
98+
}
99+
}
100+
101+
static bool test_enable_disable_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
102+
{
103+
twai_frame_t *rx_frame = user_ctx;
104+
size_t ret_len;
105+
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame->header, rx_frame->buffer, rx_frame->buffer_len, &ret_len)) {
106+
ESP_EARLY_LOGI("twai", "RX id 0x%x len %d ext %d fd %d brs %d esi %d", rx_frame->header.id, ret_len, rx_frame->header.ide, rx_frame->header.fdf, rx_frame->header.brs, rx_frame->header.esi);
107+
rx_frame->buffer += rx_frame->buffer_len;
108+
}
109+
return false;
110+
}
111+
112+
TEST_CASE("twai transmit stop resume (loopback)", "[TWAI]")
113+
{
114+
// prepare test memory
115+
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
116+
uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
117+
TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr);
118+
printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM);
119+
120+
twai_node_handle_t node_hdl;
121+
twai_onchip_node_config_t node_config = {
122+
.io_cfg.tx = TEST_TX_GPIO,
123+
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
124+
.bit_timing.bitrate = 1000000,
125+
.data_timing.bitrate = 4000000,
126+
.data_timing.ssp_permill = 700, // ssp 70.0%
127+
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
128+
.flags.enable_loopback = true,
129+
.flags.enable_self_test = true,
130+
};
131+
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
132+
133+
// reconfig fd timing to 48M/(12+5+6+1)=2MHz, ssp=20/(12+5+6+1)=83%
134+
twai_timing_advanced_config_t timing_fd = {
135+
.brp = 1,
136+
.prop_seg = 12,
137+
.tseg_1 = 5,
138+
.tseg_2 = 6,
139+
.sjw = 3,
140+
.ssp_offset = 20,
141+
};
142+
TEST_ESP_OK(twai_node_reconfig_timing(node_hdl, NULL, &timing_fd));
143+
144+
twai_frame_t rx_frame = {
145+
.buffer = recv_pkg_ptr,
146+
.buffer_len = TEST_FRAME_LEN,
147+
};
148+
twai_event_callbacks_t user_cbs = {
149+
.on_rx_done = test_enable_disable_rx_cb,
150+
};
151+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame));
152+
TEST_ESP_OK(twai_node_enable(node_hdl));
153+
154+
//create and enqueue all transfers
155+
twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT);
156+
TEST_ASSERT(tx_msgs);
157+
for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) {
158+
tx_msgs[tx_cnt].header.id = tx_cnt | 0x400;
159+
tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3);
160+
tx_msgs[tx_cnt].header.fdf = !!(tx_cnt % 4);
161+
tx_msgs[tx_cnt].header.brs = !!(tx_cnt % 2);
162+
tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN;
163+
tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN;
164+
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 500));
165+
}
166+
167+
TEST_ESP_OK(twai_node_disable(node_hdl));
168+
for (uint8_t i = 3; i > 0; i--) {
169+
printf("interrupted, %d sec\n", i);
170+
vTaskDelay(1000);
171+
}
172+
printf("continuing ...\n");
173+
TEST_ESP_OK(twai_node_enable(node_hdl));
174+
175+
//waiting pkg receive finish
176+
while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_LEN);
177+
free(tx_msgs);
178+
179+
// check if pkg receive correct
180+
printf("pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok");
181+
TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN);
182+
183+
free(send_pkg_ptr);
184+
free(recv_pkg_ptr);
185+
TEST_ESP_OK(twai_node_disable(node_hdl));
186+
TEST_ESP_OK(twai_node_delete(node_hdl));
187+
}
188+
189+
static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num)
190+
{
191+
uint8_t send_pkg_ptr[TWAIFD_FRAME_MAX_LEN];
192+
twai_frame_t tx_msg = {
193+
.buffer = send_pkg_ptr,
194+
};
195+
printf("Sending %ld random trans ...\n", trans_num);
196+
for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) {
197+
tx_msg.header.id = tx_cnt | 0xf000;
198+
tx_msg.header.ide = !!(tx_cnt % 2);
199+
tx_msg.header.rtr = !!(tx_cnt % 3);
200+
tx_msg.header.fdf = !!(tx_cnt % 5);
201+
tx_msg.buffer_len = tx_msg.header.fdf ? (tx_cnt % TWAIFD_FRAME_MAX_LEN) : (tx_cnt % TWAI_FRAME_MAX_LEN);
202+
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0));
203+
vTaskDelay(8); //as async transaction, waiting trans done
204+
}
205+
}
206+
207+
static bool test_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
208+
{
209+
uint8_t *test_ctrl = user_ctx;
210+
size_t ret_len;
211+
uint8_t recv_pkg_ptr[TWAIFD_FRAME_MAX_LEN];
212+
twai_frame_t rx_frame = {
213+
.buffer = recv_pkg_ptr,
214+
.buffer_len = TWAIFD_FRAME_MAX_LEN,
215+
};
216+
if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame.header, rx_frame.buffer, rx_frame.buffer_len, &ret_len)) {
217+
ESP_EARLY_LOGI("twai", "RX id 0x%4x len %2d ext %d rmt %d fd %d", rx_frame.header.id, ret_len, rx_frame.header.ide, rx_frame.header.rtr, rx_frame.header.fdf);
218+
switch (test_ctrl[0]) {
219+
case 0: //filter 0
220+
TEST_ASSERT(rx_frame.header.id >= 0x10);
221+
TEST_ASSERT(!rx_frame.header.ide);
222+
break;
223+
case 1:
224+
case 2: break;
225+
case 3: //filter 1
226+
TEST_ASSERT((rx_frame.header.id & 0xfff0) == 0xf000);
227+
TEST_ASSERT(rx_frame.header.ide && !rx_frame.header.fdf);
228+
break;
229+
case 4: //range filter 0
230+
TEST_ASSERT(!rx_frame.header.ide && rx_frame.header.fdf);
231+
break;
232+
default: TEST_ASSERT(false);
233+
}
234+
test_ctrl[1] ++;
235+
}
236+
return false;
237+
}
238+
239+
TEST_CASE("twai filter (loopback)", "[TWAI]")
240+
{
241+
uint8_t test_ctrl[2];
242+
twai_node_handle_t node_hdl;
243+
twai_onchip_node_config_t node_config = {
244+
.io_cfg.tx = TEST_TX_GPIO,
245+
.io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver
246+
.bit_timing.bitrate = 1000000,
247+
.tx_queue_depth = TEST_TWAI_QUEUE_DEPTH,
248+
.flags.enable_loopback = true,
249+
.flags.enable_self_test = true,
250+
};
251+
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
252+
253+
twai_event_callbacks_t user_cbs = {
254+
.on_rx_done = test_filter_rx_done_cb,
255+
};
256+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl));
257+
258+
//------------------ Filter 0 -------------------//
259+
test_ctrl[0] = 0;
260+
test_ctrl[1] = 0;
261+
printf("Testing mask filter 0\n");
262+
twai_mask_filter_config_t mfilter_cfg0 = {
263+
.id = 0x10,
264+
.mask = 0xf0,
265+
.is_ext = false,
266+
};
267+
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0));
268+
TEST_ESP_OK(twai_node_enable(node_hdl));
269+
test_random_trans_generator(node_hdl, 30);
270+
TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]); //after filter, rx frame should less than tx num
271+
272+
printf("Change to receive ALL\n");
273+
test_ctrl[0] = 1;
274+
test_ctrl[1] = 0;
275+
// set to receive ALL
276+
mfilter_cfg0.id = 0;
277+
mfilter_cfg0.mask = 0;
278+
TEST_ESP_OK(twai_node_disable(node_hdl));
279+
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0));
280+
TEST_ESP_OK(twai_node_enable(node_hdl));
281+
test_random_trans_generator(node_hdl, 30);
282+
TEST_ASSERT_EQUAL(30, test_ctrl[1]);
283+
284+
printf("Change to receive NONE\n");
285+
test_ctrl[0] = 2;
286+
test_ctrl[1] = 0;
287+
// set to receive NONE
288+
mfilter_cfg0.id = 0xFFFFFFFF;
289+
mfilter_cfg0.mask = 0xFFFFFFFF;
290+
TEST_ESP_OK(twai_node_disable(node_hdl));
291+
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0));
292+
TEST_ESP_OK(twai_node_enable(node_hdl));
293+
test_random_trans_generator(node_hdl, 30);
294+
TEST_ASSERT_EQUAL(0, test_ctrl[1]);
295+
296+
//------------------ Filter 1 -------------------//
297+
test_ctrl[0] = 3;
298+
test_ctrl[1] = 0;
299+
printf("Testing mask filter 1\n");
300+
twai_mask_filter_config_t mfilter_cfg1 = {
301+
.id = 0xf000,
302+
.mask = 0xfff0,
303+
.is_ext = true,
304+
.no_fd = true,
305+
};
306+
TEST_ESP_OK(twai_node_disable(node_hdl));
307+
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 1, &mfilter_cfg1));
308+
TEST_ESP_OK(twai_node_enable(node_hdl));
309+
test_random_trans_generator(node_hdl, 30);
310+
TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]);
311+
// set to receive NONE
312+
mfilter_cfg1.id = 0xFFFFFFFF;
313+
mfilter_cfg1.mask = 0xFFFFFFFF;
314+
TEST_ESP_OK(twai_node_disable(node_hdl));
315+
TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 1, &mfilter_cfg1));
316+
317+
//------------------ Range Filter 0 -------------------//
318+
test_ctrl[0] = 4;
319+
test_ctrl[1] = 0;
320+
printf("Testing range filter 0\n");
321+
twai_range_filter_config_t rfilter_cfg0 = {
322+
.range_low = 0,
323+
.range_high = 0xFFFFFFFF,
324+
.is_ext = false,
325+
.no_classic = true,
326+
};
327+
TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg0));
328+
TEST_ESP_OK(twai_node_enable(node_hdl));
329+
test_random_trans_generator(node_hdl, 30);
330+
TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]);
331+
332+
TEST_ESP_OK(twai_node_disable(node_hdl));
333+
TEST_ESP_OK(twai_node_delete(node_hdl));
334+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
CONFIG_FREERTOS_HZ=1000
2+
CONFIG_ESP_TASK_WDT_INIT=n

0 commit comments

Comments
 (0)