Skip to content

Commit 95b303c

Browse files
committed
Merge branch 'test/twai_new_driver_add_interactive_test' into 'master'
test(driver_twai): new driver add interctive test See merge request espressif/esp-idf!39043
2 parents 33821d1 + 69f258b commit 95b303c

File tree

6 files changed

+206
-10
lines changed

6 files changed

+206
-10
lines changed

components/esp_driver_twai/esp_twai_onchip.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,13 @@ esp_err_t twai_new_node_onchip(const twai_onchip_node_config_t *node_config, twa
636636
// Configure GPIO
637637
ESP_GOTO_ON_ERROR(_node_config_io(node, node_config), err, TAG, "gpio config failed");
638638
#if CONFIG_PM_ENABLE
639+
#if SOC_TWAI_CLK_SUPPORT_APB
640+
// DFS can change APB frequency. So add lock to prevent sleep and APB freq from changing
641+
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, twai_controller_periph_signals.controllers[ctrlr_id].module_name, &node->pm_lock), err, TAG, "init power manager failed");
642+
#else // XTAL
643+
// XTAL freq can be closed in light sleep, so we need to create a lock to prevent light sleep
639644
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, twai_controller_periph_signals.controllers[ctrlr_id].module_name, &node->pm_lock), err, TAG, "init power manager failed");
645+
#endif //SOC_TWAI_CLK_SUPPORT_APB
640646
#endif //CONFIG_PM_ENABLE
641647

642648
node->api_base.enable = _node_enable;

components/esp_driver_twai/test_apps/test_twai/main/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
set(srcs "test_app_main.c")
22

33
if(CONFIG_SOC_TWAI_SUPPORTED)
4-
list(APPEND srcs "test_twai_common.c")
4+
list(APPEND srcs "test_twai_common.c" "test_twai_network.c")
55
endif()
66

77
if(CONFIG_SOC_TWAI_SUPPORT_FD)

components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static IRAM_ATTR bool test_driver_install_rx_cb(twai_node_handle_t handle, const
3636
return false;
3737
}
3838

39-
TEST_CASE("twai install uninstall (loopback)", "[TWAI]")
39+
TEST_CASE("twai install uninstall (loopback)", "[twai]")
4040
{
4141
esp_err_t ret;
4242
twai_node_handle_t node_hdl[SOC_TWAI_CONTROLLER_NUM + 1];
@@ -145,7 +145,7 @@ static void test_twai_baudrate_correctness(twai_clock_source_t clk_src, uint32_t
145145
TEST_ESP_OK(twai_node_delete(twai_node));
146146
}
147147

148-
TEST_CASE("twai baudrate measurement", "[TWAI]")
148+
TEST_CASE("twai baudrate measurement", "[twai]")
149149
{
150150
twai_clock_source_t twai_available_clk_srcs[] = SOC_TWAI_CLKS;
151151
for (size_t i = 0; i < sizeof(twai_available_clk_srcs) / sizeof(twai_available_clk_srcs[0]); i++) {
@@ -163,7 +163,7 @@ static IRAM_ATTR bool test_enable_disable_rx_cb(twai_node_handle_t handle, const
163163
return false;
164164
}
165165

166-
TEST_CASE("twai transmit stop resume (loopback)", "[TWAI]")
166+
TEST_CASE("twai transmit stop resume (loopback)", "[twai]")
167167
{
168168
// prepare test memory
169169
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);
@@ -268,7 +268,7 @@ static IRAM_ATTR bool test_filter_rx_done_cb(twai_node_handle_t handle, const tw
268268
return false;
269269
}
270270

271-
TEST_CASE("twai mask filter (loopback)", "[TWAI]")
271+
TEST_CASE("twai mask filter (loopback)", "[twai]")
272272
{
273273
uint8_t test_ctrl[2];
274274
twai_node_handle_t node_hdl;
@@ -352,7 +352,7 @@ static IRAM_ATTR bool test_dual_filter_rx_done_cb(twai_node_handle_t handle, con
352352
return false;
353353
}
354354

355-
TEST_CASE("twai dual 16bit mask filter (loopback)", "[TWAI]")
355+
TEST_CASE("twai dual 16bit mask filter (loopback)", "[twai]")
356356
{
357357
uint8_t test_ctrl[2];
358358
twai_node_handle_t node_hdl;
@@ -421,7 +421,7 @@ static void IRAM_ATTR test_wait_trans_done_cache_disable(void *args)
421421
}
422422
}
423423

424-
TEST_CASE("twai driver cache safe (loopback)", "[TWAI]")
424+
TEST_CASE("twai driver cache safe (loopback)", "[twai]")
425425
{
426426
// prepare test memory
427427
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT);

components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ static IRAM_ATTR bool test_range_filter_rx_done_cb(twai_node_handle_t handle, co
6060
return false;
6161
}
6262

63-
TEST_CASE("twai range filter (loopback)", "[TWAI]")
63+
TEST_CASE("twai range filter (loopback)", "[twai]")
6464
{
6565
uint8_t test_ctrl[2];
6666
twai_node_handle_t node_hdl;
@@ -131,7 +131,7 @@ static IRAM_ATTR bool test_fd_trans_time_rx_cb(twai_node_handle_t handle, const
131131
return false;
132132
}
133133

134-
TEST_CASE("twai fd transmit time (loopback)", "[TWAI]")
134+
TEST_CASE("twai fd transmit time (loopback)", "[twai]")
135135
{
136136
// prepare test memory
137137
uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_TIME_BUF_LEN, MALLOC_CAP_8BIT);
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "unity.h"
8+
#include "unity_test_utils_cache.h"
9+
#include "esp_log.h"
10+
#include "freertos/FreeRTOS.h"
11+
#include "test_utils.h"
12+
#include "esp_twai.h"
13+
#include "esp_twai_onchip.h"
14+
15+
#define TEST_TX_GPIO 4
16+
#define TEST_RX_GPIO 5
17+
18+
static bool IRAM_ATTR test_listen_only_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx)
19+
{
20+
twai_frame_t *rx_frame = ((twai_frame_t **)user_ctx)[1];
21+
uint8_t *rx_cnt = ((uint8_t **)user_ctx)[0];
22+
if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) {
23+
*rx_cnt += 1;
24+
}
25+
return false;
26+
}
27+
28+
TEST_CASE("twai_listen_only", "[twai_net]")
29+
{
30+
twai_node_handle_t node_hdl;
31+
twai_onchip_node_config_t node_config = {
32+
.io_cfg.tx = TEST_TX_GPIO,
33+
.io_cfg.rx = TEST_RX_GPIO,
34+
.bit_timing.bitrate = 250000,
35+
.tx_queue_depth = 3,
36+
.flags.enable_listen_only = true,
37+
};
38+
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
39+
ESP_LOGI("Test", "driver installed");
40+
41+
uint8_t rx_buffer[8] = {0};
42+
twai_frame_t rx_frame = {
43+
.buffer = rx_buffer,
44+
.buffer_len = sizeof(rx_buffer),
45+
};
46+
uint8_t rx_msg_cnt = 0;
47+
void *user_data[2] = {&rx_msg_cnt, &rx_frame};
48+
49+
twai_event_callbacks_t user_cbs = {
50+
.on_rx_done = test_listen_only_rx_cb,
51+
};
52+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, user_data));
53+
TEST_ESP_OK(twai_node_enable(node_hdl));
54+
55+
ESP_LOGI("Test", "Listening ...");
56+
while (!rx_msg_cnt) {
57+
vTaskDelay(1);
58+
}
59+
ESP_LOGI("Test", "receive with id 0x%lx", rx_frame.header.id);
60+
ESP_LOG_BUFFER_HEX("Data", rx_frame.buffer, twaifd_dlc2len(rx_frame.header.dlc));
61+
TEST_ASSERT_EQUAL_HEX(0x6688, rx_frame.header.id);
62+
uint8_t expected_data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
63+
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_data, rx_frame.buffer, twaifd_dlc2len(rx_frame.header.dlc));
64+
65+
TEST_ESP_OK(twai_node_disable(node_hdl));
66+
TEST_ESP_OK(twai_node_delete(node_hdl));
67+
}
68+
69+
TEST_CASE("twai_remote_request", "[twai_net]")
70+
{
71+
twai_node_handle_t node_hdl;
72+
twai_onchip_node_config_t node_config = {
73+
.io_cfg.tx = TEST_TX_GPIO,
74+
.io_cfg.rx = TEST_RX_GPIO,
75+
.bit_timing.bitrate = 250000,
76+
.fail_retry_cnt = -1, // retry forever if send remote frame failed
77+
.tx_queue_depth = 3,
78+
};
79+
TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl));
80+
ESP_LOGI("Test", "driver installed");
81+
82+
uint8_t rx_buffer[8] = {0};
83+
twai_frame_t rx_frame = {
84+
.buffer = rx_buffer,
85+
.buffer_len = sizeof(rx_buffer),
86+
};
87+
uint8_t rx_msg_cnt = 0;
88+
void *user_data[2] = {&rx_msg_cnt, &rx_frame};
89+
90+
twai_event_callbacks_t user_cbs = {
91+
.on_rx_done = test_listen_only_rx_cb,
92+
};
93+
TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, user_data));
94+
TEST_ESP_OK(twai_node_enable(node_hdl));
95+
96+
twai_frame_t tx_frame = {
97+
.header.id = 0x123,
98+
.header.dlc = 8,
99+
.header.rtr = true,
100+
.header.ide = true,
101+
};
102+
TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_frame, 1000));
103+
ESP_LOGI("Test", "send remote frame");
104+
105+
uint8_t expected_data[8] = {0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10};
106+
//waiting pkg receive finish
107+
while (!rx_msg_cnt) {
108+
vTaskDelay(1);
109+
}
110+
ESP_LOGI("Test", "receive with id 0x%lx", rx_frame.header.id);
111+
ESP_LOG_BUFFER_HEX("Data", rx_frame.buffer, twaifd_dlc2len(rx_frame.header.dlc));
112+
TEST_ASSERT_EQUAL_HEX(0x123, rx_frame.header.id);
113+
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_data, rx_frame.buffer, twaifd_dlc2len(rx_frame.header.dlc));
114+
115+
TEST_ESP_OK(twai_node_disable(node_hdl));
116+
TEST_ESP_OK(twai_node_delete(node_hdl));
117+
}

components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
22
# SPDX-License-Identifier: Apache-2.0
33

4+
import subprocess
5+
from time import sleep
6+
47
import pytest
8+
from can import Bus
9+
from can import Message
510
from pytest_embedded import Dut
611
from pytest_embedded_idf.utils import idf_parametrize
712
from pytest_embedded_idf.utils import soc_filtered_targets
@@ -11,4 +16,72 @@
1116
@pytest.mark.parametrize('config', ['release', 'cache_safe'], indirect=True)
1217
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
1318
def test_driver_twai_loopbk(dut: Dut) -> None:
14-
dut.run_all_single_board_cases(reset=True)
19+
dut.run_all_single_board_cases(group='twai', reset=True)
20+
21+
22+
# -------------------------------- test twai interactive ------------------------------
23+
@pytest.fixture(name='socket_can')
24+
def fixture_create_socket_can() -> Bus:
25+
# Set up the socket CAN with the bitrate
26+
start_command = 'sudo ip link set can0 up type can bitrate 250000'
27+
stop_command = 'sudo ip link set can0 down'
28+
try:
29+
subprocess.run(start_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
30+
except Exception as e:
31+
print(f'Open bus Error: {e}')
32+
bus = Bus(interface='socketcan', channel='can0', bitrate=250000)
33+
yield bus # test invoked here
34+
bus.shutdown()
35+
subprocess.run(stop_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
36+
37+
38+
@pytest.mark.twai_std
39+
@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='no runner')
40+
@pytest.mark.parametrize('config', ['release'], indirect=True)
41+
@pytest.mark.timeout(10) # Whole test timeout
42+
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
43+
def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None:
44+
dut.serial.hard_reset()
45+
dut.expect_exact('Press ENTER to see the list of tests')
46+
47+
dut.write('"twai_listen_only"')
48+
49+
# wait the DUT to finish initialize
50+
sleep(0.1)
51+
52+
message = Message(
53+
arbitration_id=0x6688,
54+
is_extended_id=True,
55+
data=[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
56+
)
57+
print('USB Socket CAN Send:', message)
58+
socket_can.send(message, timeout=0.2)
59+
dut.expect_unity_test_output(timeout=10)
60+
61+
62+
@pytest.mark.twai_std
63+
@pytest.mark.temp_skip_ci(targets=['esp32c5'], reason='no runner')
64+
@pytest.mark.parametrize('config', ['release'], indirect=True)
65+
@pytest.mark.timeout(10) # Whole test timeout
66+
@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target'])
67+
def test_driver_twai_remote_request(dut: Dut, socket_can: Bus) -> None:
68+
dut.serial.hard_reset()
69+
dut.expect_exact('Press ENTER to see the list of tests')
70+
71+
dut.write('"twai_remote_request"')
72+
73+
print('Waiting remote frame ...')
74+
while True:
75+
req = socket_can.recv(timeout=0.2)
76+
if req is not None and req.is_remote_frame:
77+
break
78+
print(f'USB Socket CAN Received: {req}')
79+
80+
reply = Message(
81+
arbitration_id=req.arbitration_id,
82+
is_extended_id=req.is_extended_id,
83+
data=[0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10],
84+
)
85+
socket_can.send(reply, timeout=0.2)
86+
print('USB Socket CAN Replied:', reply)
87+
dut.expect_unity_test_output(timeout=10)

0 commit comments

Comments
 (0)