1 /*
2  * Copyright (c) 2023, Meta
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/console/console.h>
8 #include <zephyr/drivers/misc/devmux/devmux.h>
9 #include <zephyr/drivers/serial/uart_emul.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/ztest.h>
12 
13 #define BUF_SIZE 32
14 
15 /* array of const struct device* */
16 static const struct device *devs[] = {
17 	DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(devmux0), devices, DEVICE_DT_GET_BY_IDX, (,))};
18 
19 /* array of names, e.g. "euart0" */
20 #define PHANDLE_TO_NAME(node_id, prop, idx) DT_NODE_FULL_NAME(DT_PHANDLE_BY_IDX(node_id, prop, idx))
21 static const char *const name[] = {
22 	DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(devmux0), devices, PHANDLE_TO_NAME, (,))};
23 
24 /* array of greetings, e.g. "Hello, euart0!" */
25 #define PHANDLE_TO_TEXT(node_id, prop, idx)                                                        \
26 	"Hello, " DT_NODE_FULL_NAME(DT_PHANDLE_BY_IDX(node_id, prop, idx)) "!"
27 static const char *const text[] = {
28 	DT_FOREACH_PROP_ELEM_SEP(DT_NODELABEL(devmux0), devices, PHANDLE_TO_TEXT, (,))};
29 
ZTEST(console_switching,test_write)30 ZTEST(console_switching, test_write)
31 {
32 	size_t normal_uart = DT_PROP(DT_NODELABEL(devmux0), selected);
33 	struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux0));
34 
35 	/* for each uart_emul device */
36 	for (size_t i = 0, j = 0, N = ARRAY_SIZE(devs); i < 2 * N; i++, j++, j %= N) {
37 		if (j == normal_uart) {
38 			/* skip testing non-emul uart */
39 			continue;
40 		}
41 
42 		int ret[4];
43 		char buf[BUF_SIZE] = {0};
44 
45 		/* write text[j] to dev[j] */
46 		ret[0] = devmux_select_set(devmux_dev, j);
47 		printk("%s", text[j]);
48 		ret[1] = uart_emul_get_tx_data(devs[j], buf, ARRAY_SIZE(buf));
49 		ret[2] = devmux_select_set(devmux_dev, normal_uart);
50 
51 		zassert_ok(ret[0], "Failed to select devmux %zu", j);
52 		zassert_ok(ret[2], "Switching back to selection %zu failed", normal_uart);
53 
54 		/* verify that text[j] was written to dev[j] */
55 		TC_PRINT("wrote '%s' to %s\n", buf, name[j]);
56 
57 		zassert_equal(ret[1], strlen(text[j]), "Only wrote %d/%zu bytes of '%s'",
58 			      ret[1], strlen(text[j]), text[j]);
59 		zassert_equal(0, strcmp(text[j], buf), "Strings '%s' and '%s' do not match",
60 			      text[j], buf);
61 	}
62 }
63 
ZTEST(console_switching,test_read)64 ZTEST(console_switching, test_read)
65 {
66 	size_t normal_uart = DT_PROP(DT_NODELABEL(devmux0), selected);
67 	struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux0));
68 
69 	/* for each uart_emul device */
70 	for (size_t i = 0, j = 0, N = ARRAY_SIZE(devs); i < 2 * N; i++, j++, j %= N) {
71 		if (j == normal_uart) {
72 			/* skip testing non-emul uart */
73 			continue;
74 		}
75 
76 		int ret[4];
77 		char buf[BUF_SIZE] = {0};
78 
79 		/* read text[j] from dev[j] */
80 		ret[0] = devmux_select_set(devmux_dev, j);
81 		console_getline_init();
82 		ret[1] = uart_emul_put_rx_data(devs[j], (uint8_t *)text[j], strlen(text[j]));
83 		ret[3] = uart_emul_put_rx_data(devs[j], "\n", 1);
84 		snprintf(buf, BUF_SIZE, "%s", console_getline());
85 		ret[2] = devmux_select_set(devmux_dev, normal_uart);
86 
87 		zassert_ok(ret[0], "Failed to select devmux %zu", j);
88 		zassert_ok(ret[2], "Switching back to selection %zu failed", normal_uart);
89 
90 		/* verify that text[j] was written to dev[j] */
91 		TC_PRINT("read '%s' from %s\n", buf, name[j]);
92 
93 		zassert_equal(ret[1], strlen(text[j]), "Only put %d/%zu bytes of '%s'",
94 			      ret[1], strlen(text[j]), text[j]);
95 		zassert_equal(0, strcmp(text[j], buf), "Strings '%s' and '%s' do not match",
96 			      text[j], buf);
97 	}
98 }
99 
setup(void)100 static void *setup(void)
101 {
102 	size_t selected = DT_PROP(DT_NODELABEL(devmux1), selected);
103 	struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux1));
104 
105 	/* ensure that non-default initial selection via DT works */
106 	zassert_equal(devmux_select_get(devmux_dev), selected);
107 
108 	return NULL;
109 }
110 
before(void * arg)111 static void before(void *arg)
112 {
113 	struct device *const devmux_dev = DEVICE_DT_GET(DT_NODELABEL(devmux0));
114 
115 	zassert_ok(devmux_select_set(devmux_dev, 0));
116 	zassert_ok(devmux_select_get(devmux_dev));
117 
118 	for (size_t i = 1; i < ARRAY_SIZE(devs); ++i) {
119 		uart_emul_flush_tx_data(devs[i]);
120 	}
121 }
122 
123 ZTEST_SUITE(console_switching, NULL, setup, before, NULL, NULL);
124