1 /*
2  * Copyright (c) 2019 Vestas Wind Systems A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief PWM shell commands.
10  */
11 
12 #include <zephyr/shell/shell.h>
13 #include <zephyr/drivers/pwm.h>
14 #include <stdlib.h>
15 
16 struct args_index {
17 	uint8_t device;
18 	uint8_t channel;
19 	uint8_t period;
20 	uint8_t pulse;
21 	uint8_t flags;
22 };
23 
24 static const struct args_index args_indx = {
25 	.device = 1,
26 	.channel = 2,
27 	.period = 3,
28 	.pulse = 4,
29 	.flags = 5,
30 };
31 
cmd_cycles(const struct shell * sh,size_t argc,char ** argv)32 static int cmd_cycles(const struct shell *sh, size_t argc, char **argv)
33 {
34 	pwm_flags_t flags = 0;
35 	const struct device *dev;
36 	uint32_t period;
37 	uint32_t pulse;
38 	uint32_t channel;
39 	int err;
40 
41 	dev = shell_device_get_binding(argv[args_indx.device]);
42 	if (!dev) {
43 		shell_error(sh, "PWM device not found");
44 		return -EINVAL;
45 	}
46 
47 	channel = strtoul(argv[args_indx.channel], NULL, 0);
48 	period = strtoul(argv[args_indx.period], NULL, 0);
49 	pulse = strtoul(argv[args_indx.pulse], NULL, 0);
50 
51 	if (argc == (args_indx.flags + 1)) {
52 		flags = strtoul(argv[args_indx.flags], NULL, 0);
53 	}
54 
55 	err = pwm_set_cycles(dev, channel, period, pulse, flags);
56 	if (err) {
57 		shell_error(sh, "failed to setup PWM (err %d)",
58 			    err);
59 		return err;
60 	}
61 
62 	return 0;
63 }
64 
cmd_usec(const struct shell * sh,size_t argc,char ** argv)65 static int cmd_usec(const struct shell *sh, size_t argc, char **argv)
66 {
67 	pwm_flags_t flags = 0;
68 	const struct device *dev;
69 	uint32_t period;
70 	uint32_t pulse;
71 	uint32_t channel;
72 	int err;
73 
74 	dev = shell_device_get_binding(argv[args_indx.device]);
75 	if (!dev) {
76 		shell_error(sh, "PWM device not found");
77 		return -EINVAL;
78 	}
79 
80 	channel = strtoul(argv[args_indx.channel], NULL, 0);
81 	period = strtoul(argv[args_indx.period], NULL, 0);
82 	pulse = strtoul(argv[args_indx.pulse], NULL, 0);
83 
84 	if (argc == (args_indx.flags + 1)) {
85 		flags = strtoul(argv[args_indx.flags], NULL, 0);
86 	}
87 
88 	err = pwm_set(dev, channel, PWM_USEC(period), PWM_USEC(pulse), flags);
89 	if (err) {
90 		shell_error(sh, "failed to setup PWM (err %d)", err);
91 		return err;
92 	}
93 
94 	return 0;
95 }
96 
cmd_nsec(const struct shell * sh,size_t argc,char ** argv)97 static int cmd_nsec(const struct shell *sh, size_t argc, char **argv)
98 {
99 	pwm_flags_t flags = 0;
100 	const struct device *dev;
101 	uint32_t period;
102 	uint32_t pulse;
103 	uint32_t channel;
104 	int err;
105 
106 	dev = shell_device_get_binding(argv[args_indx.device]);
107 	if (!dev) {
108 		shell_error(sh, "PWM device not found");
109 		return -EINVAL;
110 	}
111 
112 	channel = strtoul(argv[args_indx.channel], NULL, 0);
113 	period = strtoul(argv[args_indx.period], NULL, 0);
114 	pulse = strtoul(argv[args_indx.pulse], NULL, 0);
115 
116 	if (argc == (args_indx.flags + 1)) {
117 		flags = strtoul(argv[args_indx.flags], NULL, 0);
118 	}
119 
120 	err = pwm_set(dev, channel, period, pulse, flags);
121 	if (err) {
122 		shell_error(sh, "failed to setup PWM (err %d)", err);
123 		return err;
124 	}
125 
126 	return 0;
127 }
128 
device_is_pwm_and_ready(const struct device * dev)129 static bool device_is_pwm_and_ready(const struct device *dev)
130 {
131 	return device_is_ready(dev) && DEVICE_API_IS(pwm, dev);
132 }
133 
device_name_get(size_t idx,struct shell_static_entry * entry)134 static void device_name_get(size_t idx, struct shell_static_entry *entry)
135 {
136 	const struct device *dev = shell_device_filter(idx, device_is_pwm_and_ready);
137 
138 	entry->syntax = (dev != NULL) ? dev->name : NULL;
139 	entry->handler = NULL;
140 	entry->help = NULL;
141 	entry->subcmd = NULL;
142 }
143 
144 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
145 
146 SHELL_STATIC_SUBCMD_SET_CREATE(pwm_cmds,
147 	SHELL_CMD_ARG(cycles, &dsub_device_name, "<device> <channel> <period in cycles> "
148 		      "<pulse width in cycles> [flags]", cmd_cycles, 5, 1),
149 	SHELL_CMD_ARG(usec, &dsub_device_name, "<device> <channel> <period in usec> "
150 		      "<pulse width in usec> [flags]", cmd_usec, 5, 1),
151 	SHELL_CMD_ARG(nsec, &dsub_device_name, "<device> <channel> <period in nsec> "
152 		      "<pulse width in nsec> [flags]", cmd_nsec, 5, 1),
153 	SHELL_SUBCMD_SET_END
154 );
155 
156 SHELL_CMD_REGISTER(pwm, &pwm_cmds, "PWM shell commands", NULL);
157