Files
2026-07-13 13:04:25 +08:00

145 lines
5.2 KiB
Python

# SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded_idf import CaseTester
from pytest_embedded_idf.utils import idf_parametrize
input_argv = {
'esp32': ['uart'],
'esp32s2': ['uart'],
'esp32s3': ['uart'],
'esp32c3': ['uart'],
'esp32c2': ['uart'],
'esp32c6': ['uart', 'lp_uart'],
'esp32h2': ['uart'],
'esp32p4': ['uart', 'lp_uart'],
'esp32c5': ['uart', 'lp_uart'],
'esp32c61': ['uart'],
'esp32h4': ['uart'],
'esp32s31': ['uart', 'lp_uart'],
}
def _run_uart_flow_ctrl_case(dut, case) -> None: # type: ignore
# Only the HP UART port is exercised in CI: its RX/TX borrow the console UART RX/TX pads, so the
# host can inject and observe the XON (0x11) / XOFF (0x13) characters over the console connection
# without extra wiring. The LP UART port cannot borrow the console pads (LP-only GPIOs) and would
# need UART0 to be physically wired to the LP UART pins, so it is left for manual testing only.
dut.serial.hard_reset()
dut._get_ready()
dut.confirm_write(case.index, expect_str=f'Running {case.name}...')
dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10)
dut.write('uart')
# Drive the HP UART software-flow-control case (both directions) after the 'uart' port has been selected.
# Part 1: the DUT reacts to XON/XOFF that we inject over the console connection.
dut.expect_exact('Send 0x13 (XOFF - Ctrl+S) to stop UART transmission', timeout=10)
dut.write(b'\x13')
dut.expect_exact('UART transmission stopped', timeout=25)
dut.expect_exact('Send 0x11 (XON - Ctrl+Q) to start UART transmission', timeout=10)
dut.write(b'\x11')
dut.expect_exact('UART transmission resumed', timeout=25)
# Part 2: the DUT auto-sends XOFF/XON when its RX FIFO fills/drains. It temporarily borrows the console TX
# pad, so we read the raw XOFF (0x13) then XON (0x11) bytes back over the console connection.
dut.expect_exact('Send 64 bytes to fill RX FIFO', timeout=10)
dut.write(b'A' * 64)
dut.expect(b'\x13') # XOFF
dut.expect(b'\x11') # XON
dut.expect_unity_test_output()
@pytest.mark.temp_skip_ci(targets=['esp32s3'], reason='skip due to duplication with test_uart_single_dev_psram')
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'iram_safe',
'release',
],
indirect=True,
)
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
def test_uart_single_dev(case_tester) -> None: # type: ignore
dut = case_tester.first_dut
chip_type = dut.app.target
uart_ports = input_argv.get(chip_type, [])
assert uart_ports, f"Error: Chip type '{chip_type}' is not defined in input_argv. Aborting..."
for case in case_tester.test_menu:
if 'wakeup' in case.groups:
# multi-dev cases, skip on generic runner
continue
if 'uart_flow_ctrl' in case.groups:
_run_uart_flow_ctrl_case(dut, case)
continue
if 'hp-uart-only' not in case.groups:
for uart_port in uart_ports:
dut.serial.hard_reset()
dut._get_ready()
dut.confirm_write(case.index, expect_str=f'Running {case.name}...')
dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10)
dut.write(f'{uart_port}')
dut.expect_unity_test_output()
else:
dut._run_normal_case(case, reset=True)
@pytest.mark.octal_psram
@pytest.mark.parametrize(
'config',
[
'iram_safe',
'release',
],
indirect=True,
)
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
def test_uart_single_dev_psram(case_tester) -> None: # type: ignore
dut = case_tester.first_dut
for case in case_tester.test_menu:
if 'wakeup' in case.groups:
# multi-dev cases, skip on generic runner
continue
if 'uart_flow_ctrl' in case.groups:
_run_uart_flow_ctrl_case(dut, case)
continue
dut.serial.hard_reset()
dut._get_ready()
dut.confirm_write(case.index, expect_str=f'Running {case.name}...')
dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10)
dut.write('uart')
dut.expect_unity_test_output()
# ESP32 only supports uart wakeup if signal routes through IOMUX
# ESP32S3 multi device runner has no psram IDF-12837,
@pytest.mark.temp_skip_ci(targets=['esp32', 'esp32s3'], reason='no multi-dev runner')
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='cannot pass') # TODO: IDF-15619
@pytest.mark.generic_multi_device
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
@pytest.mark.parametrize(
'config',
[
'iram_safe',
# Note: Software clock ICG (Idle Clock Gating) feature in ESP32-P4 won't work in release test.
'release',
],
indirect=True,
)
@pytest.mark.parametrize('count', [2], indirect=True)
def test_hp_uart_wakeup_modes(case_tester: CaseTester) -> None:
relevant_cases = [case for case in case_tester.test_menu if {'wakeup', 'uart'}.issubset(case.groups)]
for case in relevant_cases:
case_tester.run_multi_dev_case(case=case, reset=True)