1 /*
2 * Copyright (c) 2021 Linaro Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @addtogroup t_uart_basic
9 * @{
10 * @defgroup t_uart_fifo test_uart_pending
11 * @brief TestPurpose: test UART uart_irq_is_pending()
12 * @details
13 *
14 * Test if uart_irq_is_pending() correctly returns 0 when there are no
15 * more RX and TX pending interrupts.
16 *
17 * The test consists in disabling TX IRQ so no TX interrupts are
18 * generated and the TX IRQ pending flag is never set. At the same time
19 * RX IRQ is enabled to let received data cause a RX IRQ and so set the
20 * RX IRQ pending flag.
21 *
22 * Then a message is sent via serial to inform that the test is ready to
23 * receive serial data, which will trigger a RX IRQ.
24 *
25 * Once a RX IRQ happens RX data is read by uart_fifo_read() until there
26 * is no more RX data to be popped from FIFO and all IRQs are handled.
27 * When that happens uart_irq_is_pending() is called and must return 0,
28 * indicating there are no more pending interrupts to be processed. If 0
29 * is returned the test passes.
30 *
31 * In some cases uart_irq_is_pending() does not correctly use the IRQ
32 * pending flags to determine if there are pending interrupts, hence
33 * even tho there aren't any further RX and TX IRQs to be processed it
34 * wrongly returns 1. If 1 is returned the test fails.
35 *
36 * @}
37 */
38
39 #include "test_uart.h"
40
41 #define MAX_NUM_TRIES 512
42 #define NOT_READY 0
43
44 #define FAILED 0
45 #define PASSED 1
46 #define WAIT 2
47 static int volatile status;
48
uart_pending_callback(const struct device * dev,void * user_data)49 static void uart_pending_callback(const struct device *dev, void *user_data)
50 {
51 ARG_UNUSED(user_data);
52
53 int num_tries = 0;
54 char recv_char;
55
56 /*
57 * If the bug is not present uart_fifo_read() will pop all
58 * received data until there is no more RX data, thus
59 * uart_irq_is_pending() must correctly return 0 indicating
60 * that there are no more RX interrupts to be processed.
61 * Otherwise uart_irq_is_pending() never returns 0 even tho
62 * there is no more RX data in the RX buffer to be processed,
63 * so, in that case, the test fails after MAX_NUM_TRIES attempts.
64 */
65 status = PASSED;
66 while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
67 if (uart_irq_rx_ready(dev) == NOT_READY) {
68 if (num_tries < MAX_NUM_TRIES) {
69 num_tries++;
70 continue;
71 } else {
72 /*
73 * Bug: no more tries; uart_irq_is_pending()
74 * always returned 1 in spite of having no more
75 * RX data to be read from FIFO and no more TX
76 * data in FIFO to be sent via serial line.
77 * N.B. uart_irq_update() always returns 1, thus
78 * uart_irq_is_pending() got stuck without any
79 * real pending interrupt, i.e. no more RX and
80 * TX data to be popped or pushed from/to FIFO.
81 */
82 status = FAILED;
83 break;
84 }
85 }
86
87 while (uart_fifo_read(dev, &recv_char, 1)) {
88 /* Echo received char */
89 TC_PRINT("%c", recv_char);
90 }
91 }
92 }
93
test_pending(void)94 static int test_pending(void)
95 {
96 const struct device *const uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
97
98 if (!device_is_ready(uart_dev)) {
99 TC_PRINT("UART device not ready\n");
100 return TC_FAIL;
101 }
102
103 /*
104 * Set IRQ callback function to handle RX IRQ.
105 */
106 uart_irq_callback_set(uart_dev, uart_pending_callback);
107
108 /*
109 * Disable TX IRQ since transmitted data is not
110 * handled by uart_pending_callback() and we don't
111 * want to trigger any TX IRQ for this test.
112 */
113 uart_irq_tx_disable(uart_dev);
114
115 /*
116 * Enable RX IRQ so uart_pending_callback() can
117 * handle input data is available in RX FIFO.
118 */
119 uart_irq_rx_enable(uart_dev);
120
121 status = WAIT;
122
123 /* Inform test is ready to receive data */
124 TC_PRINT("Please send characters to serial console\n");
125
126 while (status == WAIT) {
127 /* Allow other thread/workqueue to work. */
128 k_yield();
129 /*
130 * Wait RX handler change 'status' properly:
131 * it will change to PASSED or FAILED after
132 * uart_irq_is_pending() is tested by
133 * uart_pending_callback() upon data reception.
134 */
135 }
136
137 if (status == PASSED) {
138 return TC_PASS;
139 } else {
140 return TC_FAIL;
141 }
142 }
143
144 #if CONFIG_SHELL
test_uart_pending(void)145 void test_uart_pending(void)
146 #else
147 ZTEST(uart_basic_api_pending, test_uart_pending)
148 #endif
149 {
150 #ifndef CONFIG_UART_INTERRUPT_DRIVEN
151 ztest_test_skip();
152 #endif
153 zassert_true(test_pending() == TC_PASS);
154 }
155