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 
cmd_uart_baudrate(const struct shell * sh,size_t argc,char ** argv)39 static int cmd_uart_baudrate(const struct shell *sh, size_t argc, char **argv)
40 {
41 	char *s_dev_name = argv[1];
42 	const struct device *dev;
43 	struct uart_config cfg;
44 	uint32_t baudrate;
45 	int ret;
46 
47 	dev = shell_device_get_binding(s_dev_name);
48 	if (!dev || !device_is_uart(dev)) {
49 		shell_error(sh, "UART: Device driver %s not found.", s_dev_name);
50 		return -ENODEV;
51 	}
52 
53 	baudrate = strtol(argv[2], NULL, 10);
54 	ret = uart_config_get(dev, &cfg);
55 	if (ret < 0) {
56 		shell_error(sh, "UART: Failed to get current configuration: %d", ret);
57 		return ret;
58 	}
59 	cfg.baudrate = baudrate;
60 
61 	ret = uart_configure(dev, &cfg);
62 	if (ret < 0) {
63 		shell_error(sh, "UART: Failed to configure device: %d", ret);
64 		return ret;
65 	}
66 	return 0;
67 }
68 
cmd_uart_flow_control(const struct shell * sh,size_t argc,char ** argv)69 static int cmd_uart_flow_control(const struct shell *sh, size_t argc, char **argv)
70 {
71 	char *s_dev_name = argv[1];
72 	const struct device *dev;
73 	struct uart_config cfg;
74 	uint8_t flow_control;
75 	int ret;
76 
77 	dev = shell_device_get_binding(s_dev_name);
78 	if (!dev || !device_is_uart(dev)) {
79 		shell_error(sh, "UART: Device driver %s not found.", s_dev_name);
80 		return -ENODEV;
81 	}
82 
83 	if (!strcmp(argv[2], "none")) {
84 		flow_control = UART_CFG_FLOW_CTRL_NONE;
85 	} else if (!strcmp(argv[2], "rtscts")) {
86 		flow_control = UART_CFG_FLOW_CTRL_RTS_CTS;
87 	} else if (!strcmp(argv[2], "dtrdsr")) {
88 		flow_control = UART_CFG_FLOW_CTRL_DTR_DSR;
89 	} else if (!strcmp(argv[2], "rs485")) {
90 		flow_control = UART_CFG_FLOW_CTRL_RS485;
91 	} else {
92 		shell_error(sh, "Unknown: '%s'", argv[2]);
93 		shell_help(sh);
94 		return SHELL_CMD_HELP_PRINTED;
95 	}
96 
97 	ret = uart_config_get(dev, &cfg);
98 	if (ret < 0) {
99 		shell_error(sh, "UART: Failed to get current configuration: %d", ret);
100 		return ret;
101 	}
102 	cfg.flow_ctrl = flow_control;
103 
104 	ret = uart_configure(dev, &cfg);
105 	if (ret < 0) {
106 		shell_error(sh, "UART: Failed to configure device: %d", ret);
107 		return ret;
108 	}
109 	return 0;
110 }
111 
device_name_get(size_t idx,struct shell_static_entry * entry)112 static void device_name_get(size_t idx, struct shell_static_entry *entry)
113 {
114 	const struct device *dev = shell_device_filter(idx, device_is_uart);
115 
116 	entry->syntax = (dev != NULL) ? dev->name : NULL;
117 	entry->handler = NULL;
118 	entry->help = NULL;
119 	entry->subcmd = NULL;
120 }
121 
122 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
123 
124 SHELL_STATIC_SUBCMD_SET_CREATE(sub_uart_cmds,
125 	SHELL_CMD_ARG(write, &dsub_device_name,
126 		      "Write data to the UART device\n"
127 		      "Usage: write <device> <data>",
128 		      cmd_uart_write, 3, 0),
129 	SHELL_CMD_ARG(baudrate, &dsub_device_name,
130 		      "Configure UART device baudrate\n"
131 		      "Usage: baudrate <device> <baudrate>",
132 		      cmd_uart_baudrate, 3, 0),
133 	SHELL_CMD_ARG(fc, &dsub_device_name,
134 		      "Configure UART device flow control\n"
135 		      "Usage: fc <device> <none|rtscts|dtrdsr|rs485>",
136 		      cmd_uart_flow_control, 3, 0),
137 	SHELL_SUBCMD_SET_END     /* Array terminated. */
138 );
139 
140 SHELL_CMD_REGISTER(uart, &sub_uart_cmds, "UART commands", NULL);
141