1 /*
2  * Copyright (c) 2024 Yishai Jaffe <yishai1999@gmail.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/uart.h>
8 #include <zephyr/shell/shell.h>
9 #include <stdlib.h>
10 
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(uart_shell, CONFIG_LOG_DEFAULT_LEVEL);
13 
device_is_uart(const struct device * dev)14 static bool device_is_uart(const struct device *dev)
15 {
16 	return DEVICE_API_IS(uart, dev);
17 }
18 
cmd_uart_write(const struct shell * sh,size_t argc,char ** argv)19 static int cmd_uart_write(const struct shell *sh, size_t argc, char **argv)
20 {
21 	char *s_dev_name = argv[1];
22 	const struct device *dev = shell_device_get_binding(s_dev_name);
23 
24 	if (!dev || !device_is_uart(dev)) {
25 		shell_error(sh, "UART: Device driver %s not found.", s_dev_name);
26 		return -ENODEV;
27 	}
28 
29 	char *buf = argv[2];
30 	int msg_len = strlen(buf);
31 
32 	for (int i = 0; i < msg_len; i++) {
33 		uart_poll_out(dev, buf[i]);
34 	}
35 
36 	return 0;
37 }
38 
39 
cmd_uart_read(const struct shell * sh,size_t argc,char ** argv)40 static int cmd_uart_read(const struct shell *sh, size_t argc, char **argv)
41 {
42 	char *s_dev_name = argv[1];
43 	const struct device *dev = shell_device_get_binding(s_dev_name);
44 	int ret = 0;
45 	char chr;
46 	k_timepoint_t end;
47 	uint64_t seconds;
48 
49 	if (!dev || !device_is_uart(dev)) {
50 		shell_error(sh, "UART: Device driver %s not found.", s_dev_name);
51 		return -ENODEV;
52 	}
53 
54 	seconds = shell_strtoul(argv[2], 10, &ret);
55 	if (ret != 0) {
56 		shell_help(sh);
57 		return SHELL_CMD_HELP_PRINTED;
58 	}
59 	if (seconds < 1) {
60 		return -EINVAL;
61 	}
62 	shell_info(sh, "UART: Read for %lli seconds from %s.", seconds, s_dev_name);
63 
64 	end = sys_timepoint_calc(K_SECONDS(seconds));
65 	while (!sys_timepoint_expired(end)) {
66 		ret = uart_poll_in(dev, &chr);
67 		if (ret == 0) {
68 			shell_fprintf_normal(sh, "%c", chr);
69 		}
70 		if (ret != 0 && ret != -1) {
71 			shell_error(sh, "Failed to read from UART (%d)", ret);
72 			return ret;
73 		}
74 	}
75 
76 	shell_fprintf_normal(sh, "\n");
77 
78 	return 0;
79 }
80 
81 
cmd_uart_baudrate(const struct shell * sh,size_t argc,char ** argv)82 static int cmd_uart_baudrate(const struct shell *sh, size_t argc, char **argv)
83 {
84 	char *s_dev_name = argv[1];
85 	const struct device *dev;
86 	struct uart_config cfg;
87 	uint32_t baudrate;
88 	int ret = 0;
89 
90 	dev = shell_device_get_binding(s_dev_name);
91 	if (!dev || !device_is_uart(dev)) {
92 		shell_error(sh, "UART: Device driver %s not found.", s_dev_name);
93 		return -ENODEV;
94 	}
95 
96 	baudrate = shell_strtoul(argv[2], 10, &ret);
97 	if (ret != 0) {
98 		shell_help(sh);
99 		return SHELL_CMD_HELP_PRINTED;
100 	}
101 	ret = uart_config_get(dev, &cfg);
102 	if (ret < 0) {
103 		shell_error(sh, "UART: Failed to get current configuration: %d", ret);
104 		return ret;
105 	}
106 	cfg.baudrate = baudrate;
107 
108 	ret = uart_configure(dev, &cfg);
109 	if (ret < 0) {
110 		shell_error(sh, "UART: Failed to configure device: %d", ret);
111 		return ret;
112 	}
113 	return 0;
114 }
115 
cmd_uart_flow_control(const struct shell * sh,size_t argc,char ** argv)116 static int cmd_uart_flow_control(const struct shell *sh, size_t argc, char **argv)
117 {
118 	char *s_dev_name = argv[1];
119 	const struct device *dev;
120 	struct uart_config cfg;
121 	uint8_t flow_control;
122 	int ret;
123 
124 	dev = shell_device_get_binding(s_dev_name);
125 	if (!dev || !device_is_uart(dev)) {
126 		shell_error(sh, "UART: Device driver %s not found.", s_dev_name);
127 		return -ENODEV;
128 	}
129 
130 	if (!strcmp(argv[2], "none")) {
131 		flow_control = UART_CFG_FLOW_CTRL_NONE;
132 	} else if (!strcmp(argv[2], "rtscts")) {
133 		flow_control = UART_CFG_FLOW_CTRL_RTS_CTS;
134 	} else if (!strcmp(argv[2], "dtrdsr")) {
135 		flow_control = UART_CFG_FLOW_CTRL_DTR_DSR;
136 	} else if (!strcmp(argv[2], "rs485")) {
137 		flow_control = UART_CFG_FLOW_CTRL_RS485;
138 	} else {
139 		shell_error(sh, "Unknown: '%s'", argv[2]);
140 		shell_help(sh);
141 		return SHELL_CMD_HELP_PRINTED;
142 	}
143 
144 	ret = uart_config_get(dev, &cfg);
145 	if (ret < 0) {
146 		shell_error(sh, "UART: Failed to get current configuration: %d", ret);
147 		return ret;
148 	}
149 	cfg.flow_ctrl = flow_control;
150 
151 	ret = uart_configure(dev, &cfg);
152 	if (ret < 0) {
153 		shell_error(sh, "UART: Failed to configure device: %d", ret);
154 		return ret;
155 	}
156 	return 0;
157 }
158 
device_name_get(size_t idx,struct shell_static_entry * entry)159 static void device_name_get(size_t idx, struct shell_static_entry *entry)
160 {
161 	const struct device *dev = shell_device_filter(idx, device_is_uart);
162 
163 	entry->syntax = (dev != NULL) ? dev->name : NULL;
164 	entry->handler = NULL;
165 	entry->help = NULL;
166 	entry->subcmd = NULL;
167 }
168 
169 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
170 
171 SHELL_STATIC_SUBCMD_SET_CREATE(sub_uart_cmds,
172 	SHELL_CMD_ARG(write, &dsub_device_name,
173 		      SHELL_HELP("Write data to the UART device",
174 				 "<device> <data>"),
175 		      cmd_uart_write, 3, 0),
176 	SHELL_CMD_ARG(read, &dsub_device_name,
177 		      SHELL_HELP("Read data from the UART device",
178 				 "<device> <duration in secs>"),
179 		      cmd_uart_read, 3, 0),
180 	SHELL_CMD_ARG(baudrate, &dsub_device_name,
181 		      SHELL_HELP("Configure the UART device baudrate",
182 				 "<device> <baudrate>"),
183 		      cmd_uart_baudrate, 3, 0),
184 	SHELL_CMD_ARG(fc, &dsub_device_name,
185 		      SHELL_HELP("Configure the UART device flow control",
186 				 "<device> <none|rtscts|dtrdsr|rs485>"),
187 		      cmd_uart_flow_control, 3, 0),
188 	SHELL_SUBCMD_SET_END     /* Array terminated. */
189 );
190 
191 SHELL_CMD_REGISTER(uart, &sub_uart_cmds, "UART commands", NULL);
192