From e4760364f18a784257ad422b913997752d15e93b Mon Sep 17 00:00:00 2001 From: zhujiale <945386260@qq.com> Date: Wed, 27 Nov 2024 14:48:29 +0800 Subject: [PATCH] [serial] add bypass testcase in utest --- .../drivers/{bypass.h => serial_bypass.h} | 0 components/drivers/include/rtdevice.h | 2 +- components/drivers/serial/Kconfig | 2 +- components/drivers/serial/dev_serial.c | 19 +- components/drivers/serial/serial_tty.c | 56 +----- components/lwp/terminal/Kconfig | 1 + examples/utest/testcases/Kconfig | 1 + .../testcases/drivers/serial_bypass/Kconfig | 7 + .../drivers/serial_bypass/SConscript | 11 ++ .../drivers/serial_bypass/bypass_conflict.c | 185 ++++++++++++++++++ .../drivers/serial_bypass/bypass_lower_run.c | 133 +++++++++++++ .../drivers/serial_bypass/bypass_register.c | 116 +++++++++++ .../drivers/serial_bypass/bypass_upper_run.c | 129 ++++++++++++ 13 files changed, 591 insertions(+), 71 deletions(-) rename components/drivers/include/drivers/{bypass.h => serial_bypass.h} (100%) create mode 100644 examples/utest/testcases/drivers/serial_bypass/Kconfig create mode 100644 examples/utest/testcases/drivers/serial_bypass/SConscript create mode 100644 examples/utest/testcases/drivers/serial_bypass/bypass_conflict.c create mode 100644 examples/utest/testcases/drivers/serial_bypass/bypass_lower_run.c create mode 100644 examples/utest/testcases/drivers/serial_bypass/bypass_register.c create mode 100644 examples/utest/testcases/drivers/serial_bypass/bypass_upper_run.c diff --git a/components/drivers/include/drivers/bypass.h b/components/drivers/include/drivers/serial_bypass.h similarity index 100% rename from components/drivers/include/drivers/bypass.h rename to components/drivers/include/drivers/serial_bypass.h diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 31ac5389454..fd4d3169609 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -153,7 +153,7 @@ extern "C" { #else #include "drivers/dev_serial.h" #ifdef RT_USING_SERIAL_BYPASS -#include "drivers/bypass.h" +#include "drivers/serial_bypass.h" #endif /* RT_USING_SERIAL_BYPASS */ #endif #endif /* RT_USING_SERIAL */ diff --git a/components/drivers/serial/Kconfig b/components/drivers/serial/Kconfig index 59eda6232d0..349aaeab2f2 100644 --- a/components/drivers/serial/Kconfig +++ b/components/drivers/serial/Kconfig @@ -23,5 +23,5 @@ menuconfig RT_USING_SERIAL default 64 config RT_USING_SERIAL_BYPASS bool "Using serial bypass" - default y + default n endif diff --git a/components/drivers/serial/dev_serial.c b/components/drivers/serial/dev_serial.c index 3a78ca51954..458a5b736ce 100644 --- a/components/drivers/serial/dev_serial.c +++ b/components/drivers/serial/dev_serial.c @@ -1428,7 +1428,6 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) while (1) { - rt_bool_t skip = RT_FALSE; ch = serial->ops->getc(serial); if (ch == -1) break; @@ -1436,6 +1435,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) #ifdef RT_USING_SERIAL_BYPASS if (serial->bypass && serial->bypass->upper_h && (serial->bypass->upper_h->head.next != &serial->bypass->upper_h->head)) { + rt_bool_t skip = RT_FALSE; char buf = (char)ch; int ret; rt_list_t* node = serial->bypass->upper_h->head.next; @@ -1449,10 +1449,11 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) } node = node->next; } while (node != &serial->bypass->upper_h->head); + + if (skip) + continue; } - if (skip) - continue; #endif level = rt_spin_lock_irqsave(&(serial->spinlock)); rx_fifo->buffer[rx_fifo->put_index] = ch; @@ -1478,17 +1479,7 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) rt_workqueue_dowork(serial->bypass->lower_workq, &serial->bypass->work); #endif - /** - * Invoke callback. - * First try notify if any, and if notify is existed, rx_indicate() - * is not callback. This separate the priority and makes the reuse - * of same serial device reasonable for RT console. - */ - if (serial->rx_notify.notify) - { - serial->rx_notify.notify(serial->rx_notify.dev); - } - else if (serial->parent.rx_indicate != RT_NULL) + if (serial->parent.rx_indicate != RT_NULL) { rt_size_t rx_length; diff --git a/components/drivers/serial/serial_tty.c b/components/drivers/serial/serial_tty.c index a75790d8569..dae668a2ef8 100644 --- a/components/drivers/serial/serial_tty.c +++ b/components/drivers/serial/serial_tty.c @@ -114,47 +114,6 @@ static void _setup_debug_rxind_hook(void) #endif /* LWP_DEBUG_INIT */ -static void _tty_rx_notify(struct rt_device *device) -{ - lwp_tty_t tp; - struct serial_tty_context *softc; - - tp = rt_container_of(device, struct lwp_tty, parent); - RT_ASSERT(tp); - - softc = tty_softc(tp); - - if (_ttyworkq) - rt_workqueue_submit_work(_ttyworkq, &softc->work, 0); -} - -static void _tty_rx_worker(struct rt_work *work, void *data) -{ - char input; - rt_ssize_t readbytes; - lwp_tty_t tp = data; - struct serial_tty_context *softc; - struct rt_serial_device *serial; - - tty_lock(tp); - - while (1) - { - softc = tty_softc(tp); - serial = softc->parent; - readbytes = rt_device_read(&serial->parent, -1, &input, 1); - if (readbytes != 1) - { - break; - } - - ttydisc_rint(tp, input, 0); - } - - ttydisc_rint_done(tp); - tty_unlock(tp); -} -#ifdef RT_USING_SERIAL_BYPASS static rt_err_t _serial_ty_bypass(struct rt_serial_device* serial, char ch,void *data) { lwp_tty_t tp; @@ -168,23 +127,11 @@ static rt_err_t _serial_ty_bypass(struct rt_serial_device* serial, char ch,void return RT_EOK; } -#endif + rt_inline void _setup_serial(struct rt_serial_device* serial, lwp_tty_t tp, struct serial_tty_context *softc) { -#ifndef RT_USING_SERIAL_BYPASS - struct rt_device_notify notify; - - softc->backup_notify = serial->rx_notify; - notify.dev = &tp->parent; - notify.notify = _tty_rx_notify; - - rt_device_init(&serial->parent); - - rt_device_control(&serial->parent, RT_DEVICE_CTRL_NOTIFY_SET, ¬ify); -#else rt_bypass_lower_register(serial, "tty",RT_BYPASS_PROTECT_LEVEL_1, _serial_ty_bypass,(void *)tp); -#endif } rt_inline void _restore_serial(struct rt_serial_device *serial, lwp_tty_t tp, @@ -363,7 +310,6 @@ rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial) { _serial_tty_set_speed(tty); rc = lwp_tty_register(tty, dev_name); - rt_work_init(&softc->work, _tty_rx_worker, tty); if (rc != RT_EOK) { diff --git a/components/lwp/terminal/Kconfig b/components/lwp/terminal/Kconfig index 7fd77e75055..a62df007538 100644 --- a/components/lwp/terminal/Kconfig +++ b/components/lwp/terminal/Kconfig @@ -2,6 +2,7 @@ menuconfig LWP_USING_TERMINAL bool "Terminal I/O Subsystem" depends on RT_USING_SMART default y + select RT_USING_SERIAL_BYPASS if LWP_USING_TERMINAL config LWP_PTY_MAX_PARIS_LIMIT diff --git a/examples/utest/testcases/Kconfig b/examples/utest/testcases/Kconfig index d28c0e9600f..4f66474c705 100644 --- a/examples/utest/testcases/Kconfig +++ b/examples/utest/testcases/Kconfig @@ -11,6 +11,7 @@ rsource "utest/Kconfig" rsource "kernel/Kconfig" rsource "cpp11/Kconfig" rsource "drivers/serial_v2/Kconfig" +rsource "drivers/serial_bypass/Kconfig" rsource "drivers/ipc/Kconfig" rsource "posix/Kconfig" rsource "mm/Kconfig" diff --git a/examples/utest/testcases/drivers/serial_bypass/Kconfig b/examples/utest/testcases/drivers/serial_bypass/Kconfig new file mode 100644 index 00000000000..149a2a9d95c --- /dev/null +++ b/examples/utest/testcases/drivers/serial_bypass/Kconfig @@ -0,0 +1,7 @@ +menu "Serial-Bypass Testcase" + +config UTEST_SERIAL_BYPASS + bool "Serial testcase" + default n + +endmenu diff --git a/examples/utest/testcases/drivers/serial_bypass/SConscript b/examples/utest/testcases/drivers/serial_bypass/SConscript new file mode 100644 index 00000000000..86be64011bf --- /dev/null +++ b/examples/utest/testcases/drivers/serial_bypass/SConscript @@ -0,0 +1,11 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('bypass*.c') + +CPPPATH = [cwd] + +group = DefineGroup('utestcases', src, depend = ['UTEST_SERIAL_BYPASS'], CPPPATH = CPPPATH) + +Return('group') diff --git a/examples/utest/testcases/drivers/serial_bypass/bypass_conflict.c b/examples/utest/testcases/drivers/serial_bypass/bypass_conflict.c new file mode 100644 index 00000000000..175a45a108d --- /dev/null +++ b/examples/utest/testcases/drivers/serial_bypass/bypass_conflict.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-11-20 zhujiale the first version + */ +#include +#include +#include "utest.h" + +static struct rt_serial_device* _serial0; +static struct rt_spinlock lock; +static int cnt = 0; + +#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x))) +#define UART_FR(base) __REG32(base + 0x18) +#define UART_DR(base) __REG32(base + 0x00) +#define UARTFR_TXFF 0x20 + +static rt_err_t utest_get_c(struct rt_serial_device* serial, char ch, void* data) +{ + rt_atomic_add(&cnt, 1); + return RT_EOK; +} + +static int utest_getc(struct rt_serial_device* serial) +{ + static int num = 0; + + rt_spin_lock(&lock); + if (rt_atomic_load(&num) == 10) + { + rt_atomic_flag_clear(&num); + rt_spin_unlock(&lock); + return -1; + } + rt_atomic_add(&num, 1); + rt_spin_unlock(&lock); + return 'a'; +} + +struct hw_uart_device +{ + rt_size_t hw_base; + rt_size_t irqno; +}; + +static int uart_putc(struct rt_serial_device* serial, char c) +{ + struct hw_uart_device* uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device*)serial->parent.user_data; + + while (UART_FR(uart->hw_base) & UARTFR_TXFF); + UART_DR(uart->hw_base) = c; + + return 1; +} + +static const struct rt_uart_ops _utest_ops = +{ + RT_NULL, + RT_NULL, + uart_putc, + utest_getc, +}; + + +static void thread_rx1(void* parameter) +{ + for (int i = 0; i < 10; i++) + { + rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND); + } +} + +static void thread_rx2(void* parameter) +{ + for (int i = 0; i < 10; i++) + { + rt_workqueue_dowork(_serial0->bypass->lower_workq, &_serial0->bypass->work); + } +} + +static void thread_high_priority(void* parameter) +{ + for (int i = 1; i < 10; i++) + { + rt_bypass_upper_register(_serial0, "test", i, utest_get_c, RT_NULL); + rt_bypass_upper_unregister(_serial0, i); + } +} + +static void thread_low_priority(void* parameter) +{ + for (int i = 0; i < 20; i++) + { + rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND); + } +} + +static void bypass_rx_stress_003(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + + rt_thread_t high = rt_thread_create("high_prio", thread_high_priority, RT_NULL, 2048, 15, 10); + rt_thread_t low = rt_thread_create("low_prio", thread_low_priority, RT_NULL, 2048, 20, 10); + + rt_atomic_flag_clear(&cnt); + _serial0->ops = &_utest_ops; + rt_bypass_upper_register(_serial0, "test", 0, utest_get_c, RT_NULL); + + rt_thread_startup(high); + rt_thread_startup(low); + + rt_thread_mdelay(1000); + _serial0->ops = tmp; + rt_bypass_upper_unregister(_serial0, 0); + uassert_true(rt_atomic_load(&cnt) == 200); +} + +static void bypass_rx_stress_002(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + rt_thread_t rx2 = rt_thread_create("rx2", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + rt_thread_t rx3 = rt_thread_create("rx3", thread_rx2, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + + rt_atomic_flag_clear(&cnt); + _serial0->ops = &_utest_ops; + rt_bypass_lower_register(_serial0, "utest", 0, utest_get_c, RT_NULL); + + rt_thread_startup(rx2); + rt_thread_startup(rx3); + + rt_thread_mdelay(1000); + + uassert_true(rt_atomic_load(&cnt) == 100); + _serial0->ops = tmp; + rt_bypass_lower_unregister(_serial0, 0); +} + +static void bypass_rx_stress_001(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + rt_thread_t rx1 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + rt_thread_t rx2 = rt_thread_create("rx1", thread_rx1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + + cnt = 0; + _serial0->ops = &_utest_ops; + rt_bypass_upper_register(_serial0, "utest", 0, utest_get_c, RT_NULL); + + rt_thread_startup(rx1); + rt_thread_startup(rx2); + + rt_thread_mdelay(1000); + + uassert_true(rt_atomic_load(&cnt) == 200); + _serial0->ops = tmp; + rt_bypass_upper_unregister(_serial0, 0); +} + +static rt_err_t utest_tc_init(void) +{ + _serial0 = (struct rt_serial_device*)rt_console_get_device(); + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void _testcase(void) +{ + UTEST_UNIT_RUN(bypass_rx_stress_001); + UTEST_UNIT_RUN(bypass_rx_stress_002); + UTEST_UNIT_RUN(bypass_rx_stress_003); +} + +UTEST_TC_EXPORT(_testcase, "testcase.bypass.conflict.001", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/drivers/serial_bypass/bypass_lower_run.c b/examples/utest/testcases/drivers/serial_bypass/bypass_lower_run.c new file mode 100644 index 00000000000..5cfb3cc197a --- /dev/null +++ b/examples/utest/testcases/drivers/serial_bypass/bypass_lower_run.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-11-20 zhujiale the first version + */ +#include +#include +#include "utest.h" + +static struct rt_serial_device* _serial0; +static int cnt = 0; + +#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x))) +#define UART_FR(base) __REG32(base + 0x18) +#define UART_DR(base) __REG32(base + 0x00) +#define UARTFR_TXFF 0x20 + +struct hw_uart_device +{ + rt_size_t hw_base; + rt_size_t irqno; +}; + +static int uart_putc(struct rt_serial_device* serial, char c) +{ + struct hw_uart_device* uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device*)serial->parent.user_data; + + while (UART_FR(uart->hw_base) & UARTFR_TXFF); + UART_DR(uart->hw_base) = c; + + return 1; +} + +static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data) +{ + static rt_uint8_t num = 0; + num++; + uassert_true(ch == ('a' + num)); + return RT_EOK; +} + +static int utest_getc_2(struct rt_serial_device* serial) +{ + static rt_uint8_t num = 0; + if (num == 20) + return -1; + num++; + return 'a' + num; +} + +static const struct rt_uart_ops _utest_ops2 = +{ + RT_NULL, + RT_NULL, + uart_putc, + utest_getc_2, +}; + +static rt_err_t utest_lower_run(struct rt_serial_device* serial, char ch, void* data) +{ + uassert_true(ch == 'a'); + cnt++; + return RT_EOK; +} + + +static int utest_getc(struct rt_serial_device* serial) +{ + static rt_uint8_t num = 0; + if (num == 10) + return -1; + num++; + return 'a'; +} + +static const struct rt_uart_ops _utest_ops = +{ + RT_NULL, + RT_NULL, + uart_putc, + utest_getc, +}; +static void bypass_lower_001(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + _serial0->ops = &_utest_ops; + rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run, RT_NULL); + + rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND); + rt_thread_mdelay(100); + uassert_true(cnt == 10); + _serial0->ops = tmp; + rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL); +} + +static void bypass_lower_002(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + _serial0->ops = &_utest_ops2; + rt_bypass_lower_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL); + + rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND); + rt_thread_mdelay(100); + uassert_true(cnt == 10); + _serial0->ops = tmp; + rt_bypass_lower_unregister(_serial0, RT_BYPASS_MAX_LEVEL); +} + +static rt_err_t utest_tc_init(void) +{ + _serial0 = (struct rt_serial_device*)rt_console_get_device(); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void _testcase(void) +{ + UTEST_UNIT_RUN(bypass_lower_001); + UTEST_UNIT_RUN(bypass_lower_002); +} + +UTEST_TC_EXPORT(_testcase, "testcase.bypass.lower.001", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/drivers/serial_bypass/bypass_register.c b/examples/utest/testcases/drivers/serial_bypass/bypass_register.c new file mode 100644 index 00000000000..df4e07b9aa2 --- /dev/null +++ b/examples/utest/testcases/drivers/serial_bypass/bypass_register.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-11-20 zhujiale the first version + */ +#include +#include +#include "utest.h" + +static struct rt_serial_device* _serial0; +static struct rt_spinlock lock; + +static rt_err_t utest_001_run(struct rt_serial_device* serial, char ch, void* data) +{ + return 0; +} + +static void thread_serial_register1(void* parameter) +{ + for (int i = 2; i < 10; i += 2) + { + rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL); + } +} + +static void thread_serial_register_upper(void* parameter) +{ + for (int i = 1; i < 10; i++) + { + rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL); + } +} + +static void thread_serial_register_lower(void* parameter) +{ + for (int i = 1; i < 10; i++) + { + rt_bypass_lower_register(_serial0, "test", i, utest_001_run, RT_NULL); + } +} + +static void bypass_register_001(void) +{ + rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register1, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL); + rt_thread_startup(t1); + for (int i = 1; i < 10; i += 2) + { + rt_bypass_upper_register(_serial0, "test", i, utest_001_run, RT_NULL); + } + rt_thread_mdelay(1000); + rt_list_t* node = _serial0->bypass->upper_h->head.next; + for (int i = 0; i < 10;i++) + { + rt_list_t* next = node->next; + struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node); + uassert_true(temp->level == i); + rt_bypass_upper_unregister(_serial0, temp->level); + node = next; + } + +} + +static void bypass_register_002(void) +{ + rt_thread_t t1 = rt_thread_create("serial_register", thread_serial_register_upper, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + rt_thread_t t2 = rt_thread_create("serial_register", thread_serial_register_lower, RT_NULL, 2048, RT_THREAD_PRIORITY_MAX - 5, 10); + rt_bypass_upper_register(_serial0, "test", 0, utest_001_run, RT_NULL); + + rt_thread_startup(t1); + rt_thread_startup(t2); + + rt_thread_mdelay(1000); + rt_list_t* node = _serial0->bypass->upper_h->head.next; + for (int i = 0; i < 10;i++) + { + rt_list_t* next = node->next; + struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node); + uassert_true(temp->level == i); + rt_bypass_upper_unregister(_serial0, temp->level); + node = next; + } + node = _serial0->bypass->lower_h->head.next; + for (int i = 1; i < 10;i++) + { + rt_list_t* next = node->next; + struct rt_serial_bypass_func* temp = rt_container_of(node, struct rt_serial_bypass_func, node); + uassert_true(temp->level == i); + rt_bypass_lower_unregister(_serial0, temp->level); + node = next; + } +} + +static rt_err_t utest_tc_init(void) +{ + _serial0 = (struct rt_serial_device*)rt_console_get_device(); + rt_spin_lock_init(&lock); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void _testcase(void) +{ + UTEST_UNIT_RUN(bypass_register_001); + UTEST_UNIT_RUN(bypass_register_002); +} + +UTEST_TC_EXPORT(_testcase, "testcase.bypass.register.001", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/drivers/serial_bypass/bypass_upper_run.c b/examples/utest/testcases/drivers/serial_bypass/bypass_upper_run.c new file mode 100644 index 00000000000..c5c14996875 --- /dev/null +++ b/examples/utest/testcases/drivers/serial_bypass/bypass_upper_run.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2006-2024 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-11-20 zhujiale the first version + */ +#include +#include +#include "utest.h" + +static struct rt_serial_device* _serial0; +static int cnt; + +#define __REG32(x) (*((volatile unsigned int*)((rt_ubase_t)x))) +#define UART_FR(base) __REG32(base + 0x18) +#define UART_DR(base) __REG32(base + 0x00) +#define UARTFR_TXFF 0x20 +static rt_err_t utest_upper_run(struct rt_serial_device* serial, char ch, void* data) +{ + uassert_true(ch == 'a'); + cnt++; + return RT_EOK; +} + +static int utest_getc(struct rt_serial_device* serial) +{ + static rt_uint8_t num = 0; + if (num == 10) + return -1; + num++; + return 'a'; +} + +struct hw_uart_device +{ + rt_size_t hw_base; + rt_size_t irqno; +}; + +static int uart_putc(struct rt_serial_device* serial, char c) +{ + struct hw_uart_device* uart; + + RT_ASSERT(serial != RT_NULL); + uart = (struct hw_uart_device*)serial->parent.user_data; + + while (UART_FR(uart->hw_base) & UARTFR_TXFF); + UART_DR(uart->hw_base) = c; + + return 1; +} + +static const struct rt_uart_ops _utest_ops = +{ + RT_NULL, + RT_NULL, + uart_putc, + utest_getc, +}; + +static rt_err_t utest_lower_run_test2(struct rt_serial_device* serial, char ch, void* data) +{ + static rt_uint8_t num = 0; + num++; + uassert_true(ch == ('a' + num)); + return RT_EOK; +} + +static int utest_getc_2(struct rt_serial_device* serial) +{ + static rt_uint8_t num = 0; + if (num == 20) + return -1; + num++; + return 'a' + num; +} + +static const struct rt_uart_ops _utest_ops2 = +{ + RT_NULL, + RT_NULL, + uart_putc, + utest_getc_2, +}; +static void bypass_upper_001(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + _serial0->ops = &_utest_ops; + rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_LEVEL_1, utest_upper_run, RT_NULL); + rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND); + uassert_true(cnt == 10); + _serial0->ops = tmp; + rt_bypass_upper_unregister(_serial0, RT_BYPASS_LEVEL_1); +} + +static void bypass_upper_002(void) +{ + const struct rt_uart_ops* tmp = _serial0->ops; + _serial0->ops = &_utest_ops2; + rt_bypass_upper_register(_serial0, "utest", RT_BYPASS_MAX_LEVEL, utest_lower_run_test2, RT_NULL); + + rt_hw_serial_isr(_serial0, RT_SERIAL_EVENT_RX_IND); + rt_thread_mdelay(100); + uassert_true(cnt == 10); + _serial0->ops = tmp; + rt_bypass_upper_unregister(_serial0, RT_BYPASS_MAX_LEVEL); +} + +static rt_err_t utest_tc_init(void) +{ + _serial0 = (struct rt_serial_device*)rt_console_get_device(); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void _testcase(void) +{ + UTEST_UNIT_RUN(bypass_upper_001); + UTEST_UNIT_RUN(bypass_upper_002); +} + +UTEST_TC_EXPORT(_testcase, "testcase.bypass.upper.001", utest_tc_init, utest_tc_cleanup, 10);