1 /*
2  * Copyright (c) 2018 Intel Corporation
3  * Copyright (c) 2021 Dennis Ruffer <daruffer@gmail.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Use "device list" command for GPIO port names
8  */
9 
10 #include <zephyr/sys/printk.h>
11 #include <zephyr/shell/shell.h>
12 #include <zephyr/init.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <zephyr/logging/log.h>
19 
20 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
21 
22 LOG_MODULE_REGISTER(gpio_shell);
23 
24 struct args_index {
25 	uint8_t port;
26 	uint8_t index;
27 	uint8_t mode;
28 	uint8_t value;
29 };
30 
31 static const struct args_index args_indx = {
32 	.port = 1,
33 	.index = 2,
34 	.mode = 3,
35 	.value = 3,
36 };
37 
cmd_gpio_conf(const struct shell * sh,size_t argc,char ** argv)38 static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv)
39 {
40 	uint8_t index = 0U;
41 	int type = GPIO_OUTPUT;
42 	const struct device *dev;
43 
44 	if (isdigit((unsigned char)argv[args_indx.index][0]) != 0 &&
45 	    isalpha((unsigned char)argv[args_indx.mode][0]) != 0) {
46 		index = (uint8_t)atoi(argv[args_indx.index]);
47 		if (!strcmp(argv[args_indx.mode], "in")) {
48 			type = GPIO_INPUT;
49 		} else if (!strcmp(argv[args_indx.mode], "inu")) {
50 			type = GPIO_INPUT | GPIO_PULL_UP;
51 		} else if (!strcmp(argv[args_indx.mode], "ind")) {
52 			type = GPIO_INPUT | GPIO_PULL_DOWN;
53 		} else if (!strcmp(argv[args_indx.mode], "out")) {
54 			type = GPIO_OUTPUT;
55 		} else {
56 			return 0;
57 		}
58 	} else {
59 		shell_error(sh, "Wrong parameters for conf");
60 		return -ENOTSUP;
61 	}
62 
63 	dev = device_get_binding(argv[args_indx.port]);
64 
65 	if (dev != NULL) {
66 		index = (uint8_t)atoi(argv[args_indx.index]);
67 		shell_print(sh, "Configuring %s pin %d",
68 			    argv[args_indx.port], index);
69 		gpio_pin_configure(dev, index, type);
70 	}
71 
72 	return 0;
73 }
74 
cmd_gpio_get(const struct shell * sh,size_t argc,char ** argv)75 static int cmd_gpio_get(const struct shell *sh,
76 			size_t argc, char **argv)
77 {
78 	const struct device *dev;
79 	uint8_t index = 0U;
80 	int rc;
81 
82 	if (isdigit((unsigned char)argv[args_indx.index][0]) != 0) {
83 		index = (uint8_t)atoi(argv[args_indx.index]);
84 	} else {
85 		shell_error(sh, "Wrong parameters for get");
86 		return -EINVAL;
87 	}
88 
89 	dev = device_get_binding(argv[args_indx.port]);
90 
91 	if (dev != NULL) {
92 		index = (uint8_t)atoi(argv[2]);
93 		shell_print(sh, "Reading %s pin %d",
94 			    argv[args_indx.port], index);
95 		rc = gpio_pin_get(dev, index);
96 		if (rc >= 0) {
97 			shell_print(sh, "Value %d", rc);
98 		} else {
99 			shell_error(sh, "Error %d reading value", rc);
100 			return -EIO;
101 		}
102 	}
103 
104 	return 0;
105 }
106 
cmd_gpio_set(const struct shell * sh,size_t argc,char ** argv)107 static int cmd_gpio_set(const struct shell *sh,
108 			size_t argc, char **argv)
109 {
110 	const struct device *dev;
111 	uint8_t index = 0U;
112 	uint8_t value = 0U;
113 
114 	if (isdigit((unsigned char)argv[args_indx.index][0]) != 0 &&
115 	    isdigit((unsigned char)argv[args_indx.value][0]) != 0) {
116 		index = (uint8_t)atoi(argv[args_indx.index]);
117 		value = (uint8_t)atoi(argv[args_indx.value]);
118 	} else {
119 		shell_print(sh, "Wrong parameters for set");
120 		return -EINVAL;
121 	}
122 	dev = device_get_binding(argv[args_indx.port]);
123 
124 	if (dev != NULL) {
125 		index = (uint8_t)atoi(argv[2]);
126 		shell_print(sh, "Writing to %s pin %d",
127 			    argv[args_indx.port], index);
128 		gpio_pin_set(dev, index, value);
129 	}
130 
131 	return 0;
132 }
133 
134 
135 /* 500 msec = 1/2 sec */
136 #define SLEEP_TIME_MS   500
137 
cmd_gpio_blink(const struct shell * sh,size_t argc,char ** argv)138 static int cmd_gpio_blink(const struct shell *sh,
139 			  size_t argc, char **argv)
140 {
141 	const struct device *dev;
142 	uint8_t index = 0U;
143 	uint8_t value = 0U;
144 	size_t count = 0;
145 	char data;
146 
147 	if (isdigit((unsigned char)argv[args_indx.index][0]) != 0) {
148 		index = (uint8_t)atoi(argv[args_indx.index]);
149 	} else {
150 		shell_error(sh, "Wrong parameters for blink");
151 		return -EINVAL;
152 	}
153 	dev = device_get_binding(argv[args_indx.port]);
154 
155 	if (dev != NULL) {
156 		index = (uint8_t)atoi(argv[2]);
157 		shell_fprintf(sh, SHELL_NORMAL, "Blinking port %s index %d.", argv[1], index);
158 		shell_fprintf(sh, SHELL_NORMAL, " Hit any key to exit");
159 
160 		/* dummy read to clear any pending input */
161 		(void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count);
162 
163 		while (true) {
164 			(void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count);
165 			if (count != 0) {
166 				break;
167 			}
168 			gpio_pin_set(dev, index, value);
169 			value = !value;
170 			k_msleep(SLEEP_TIME_MS);
171 		}
172 
173 		shell_fprintf(sh, SHELL_NORMAL, "\n");
174 	}
175 
176 	return 0;
177 }
178 
179 SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio,
180 			       SHELL_CMD_ARG(conf, NULL, "Configure GPIO", cmd_gpio_conf, 4, 0),
181 			       SHELL_CMD_ARG(get, NULL, "Get GPIO value", cmd_gpio_get, 3, 0),
182 			       SHELL_CMD_ARG(set, NULL, "Set GPIO", cmd_gpio_set, 4, 0),
183 			       SHELL_CMD_ARG(blink, NULL, "Blink GPIO", cmd_gpio_blink, 3, 0),
184 			       SHELL_SUBCMD_SET_END /* Array terminated. */
185 			       );
186 
187 SHELL_CMD_REGISTER(gpio, &sub_gpio, "GPIO commands", NULL);
188