]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_gpio.c
Rename: 'fat stat' to 'fat status'
[z180-stamp.git] / avr / cmd_gpio.c
CommitLineData
35edb766
L
1/*
2 * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
3 *
fcf1d5b3 4 * SPDX-License-Identifier: GPL-2.0
35edb766
L
5 */
6
7eecbdac 7#include "cmd_gpio.h"
8f23e84c 8#include <ctype.h>
8f23e84c 9
8f23e84c
L
10#include "print-utils.h"
11#include "getopt-min.h"
12#include "env.h"
05994bd9 13#include "gpio.h"
8f23e84c
L
14//#include "debug.h"
15
16
972e6e9b 17static uint_fast8_t pinnames_get(char *pin_names[GPIO_MAX+1])
8f23e84c
L
18{
19 static const FLASH char delim1[] = {":= "};
20 static const FLASH char delim2[] = {", "};
972e6e9b 21 uint_fast8_t width = 0;
8f23e84c 22 char *lp;
8f23e84c
L
23 uint_fast8_t i;
24
972e6e9b 25 memset(pin_names, 0, (GPIO_MAX+1) * sizeof(char *));
8f23e84c 26
612a6965 27/* TODO: enters endless loop on wrong parameters */
4565be9a 28
972e6e9b
L
29 lp = getenv_str(PSTR(ENV_PINALIAS));
30 if (lp != NULL) {
31 pin_names[GPIO_MAX] = strdup(lp);
32 if (pin_names[GPIO_MAX] != NULL) {
33 char *ptr = strtok_P(pin_names[GPIO_MAX], delim1);
34 while (ptr != NULL) {
35 if (((i = strtoul(ptr, &lp, 10)) < GPIO_MAX) &&
36 lp != ptr &&
37 (ptr = strtok_P(NULL, delim2)) != NULL ) {
38 pin_names[i] = ptr;
39 ptr = strtok_P(NULL, delim1);
40 }
8f23e84c 41 }
8f23e84c 42
972e6e9b
L
43 for (i = 0; i < GPIO_MAX; i++)
44 if (strlen(pin_names[i]) > width)
45 width = strlen(pin_names[i]);
46 }
8f23e84c 47 }
972e6e9b 48 return width;
8f23e84c
L
49}
50
51
52static size_t xstrlen(char *s)
53{
54 if (s == NULL)
55 return 0;
56 else
57 return strlen(s);
58}
59
60static const FLASH char * const FLASH pinconf_str[] = {
61 FSTR("?"),
62 FSTR("Input"),
63 FSTR("Pullup"),
64 FSTR("Output"),
65 FSTR("Clock"),
66 };
67
68static const FLASH char * const FLASH pinlevel_str[] = {
69 FSTR("Low"),
70 FSTR("High"),
71 FSTR(""),
72 };
73
972e6e9b 74static void print_pin(uint8_t pin, uint_fast8_t multi, char *pin_names[], uint_fast8_t pn_width)
8f23e84c 75{
972e6e9b 76 gpiomode_t pinconf;
8f23e84c
L
77 const FLASH char *levelp;
78 long div;
79
05994bd9 80 pinconf = gpio_config_get(pin);
8f23e84c 81 if (pinconf == OUTPUT_TIMER) {
05994bd9 82 div = gpio_clockdiv_get(pin);
8f23e84c
L
83 levelp = pinlevel_str[2];
84 } else
05994bd9 85 levelp = pinlevel_str[gpio_read(pin)];
8f23e84c
L
86
87 if (multi) {
88 printf_P(PSTR("%3d "), pin);
972e6e9b 89 if (pn_width) {
8f23e84c 90 printf_P(PSTR("%s "), pin_names[pin]);
972e6e9b 91 print_blanks(pn_width - xstrlen(pin_names[pin]));
8f23e84c
L
92 }
93 my_puts_P(pinconf_str[pinconf]);
94 print_blanks(7 - strlen_P(pinconf_str[pinconf]));
95 my_puts_P(levelp);
96 print_blanks(5 - strlen_P(levelp));
97 if (pinconf == OUTPUT_TIMER)
98 printf_P(PSTR("%8ld %8ld"),
99 div, F_CPU/div);
100 } else {
101 printf_P(PSTR("%d: \"%s\", "), pin, pin_names[pin] ? pin_names[pin] : 0);
102 my_puts_P(pinconf_str[pinconf]);
972e6e9b 103 my_puts_P(PSTR(", "));
8f23e84c
L
104 my_puts_P(levelp);
105
106 if (pinconf == OUTPUT_TIMER)
107 printf_P(PSTR("divide by %ld (%ldHz)"),
108 div, F_CPU/div);
109 }
972e6e9b 110 my_puts_P(PSTR("\n"));
8f23e84c
L
111}
112
972e6e9b 113static int_fast8_t pinarg_insert(uint8_t pin, uint_fast8_t count, uint_fast8_t pinarg[])
8f23e84c
L
114{
115 uint_fast8_t pos;
116
972e6e9b 117 if (pin >= GPIO_MAX)
8f23e84c
L
118 return -1;
119
120 for (pos = 0; pos < count; pos++) {
121 if (pin == pinarg[pos])
122 return 0;
123 if (pin < pinarg[pos])
124 break;
125 }
126 for (uint_fast8_t i = count-1; i == pos ; i--)
127 pinarg[i+1] = pinarg[i];
128 pinarg[pos] = pin;
129
130 return 1;
131}
132
133static uint_fast8_t pinarg_get(char * arg, uint_fast8_t pinarg[])
134{
135 char *endp;
136 uint_fast8_t pin1;
137 int_fast8_t rc;
138 uint_fast8_t count = 0;
139
140 while (1) {
141 pin1 = strtoul(arg, &endp, 10);
142 if (endp != arg && *endp == '-') {
143 arg = endp+1;
144 uint_fast8_t pin2 = (int) strtoul(arg, &endp, 10);
145 if (pin1 < pin2)
146 for (; pin1 < pin2; pin1++)
147 if ((rc = pinarg_insert(pin1, count, pinarg)) >= 0)
148 count += rc;
149 else
150 return 0;
151 else
152 return 0;
153 }
154 if (endp != arg) {
155 if ((*endp == ',' || *endp == '\0') &&
156 (rc = pinarg_insert(pin1, count, pinarg)) >= 0) {
157 count += rc;
158 if (*endp == '\0')
159 return count;
160 } else
161 return 0;
162 } else
163 return 0;
164
165 arg = endp+1;
166 }
167}
168
169
972e6e9b 170command_ret_t do_gpio(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char *const argv[])
8f23e84c 171{
972e6e9b 172 uint_fast8_t printheader = 1;
05994bd9 173 uint_fast8_t pinarg[GPIO_MAX];
8f23e84c
L
174 uint_fast8_t pinargc;
175
8f23e84c 176 /* reset getopt() */
beafa6d6 177 optind = 0;
8f23e84c
L
178
179 int opt;
180 while ((opt = getopt(argc, argv, PSTR("s"))) != -1) {
181 switch (opt) {
182 case 's':
183 printheader = 0;
184 break;
185 default: /* '?' */
186 return CMD_RET_USAGE;
187 }
188 }
189
190 /* remaining arguments */
191 argc -= optind;
192
8f23e84c 193 if (argc == 0) {
972e6e9b 194 /* print config of all pins */
05994bd9 195 for (pinargc = 0; pinargc < GPIO_MAX; pinargc++)
8f23e84c
L
196 pinarg[pinargc] = pinargc;
197 } else {
198 /* get first arg */
199 pinargc = pinarg_get(argv[optind++], pinarg);
200 if (pinargc == 0)
201 return CMD_RET_USAGE;
202 else
203 argc--;
204 }
205
972e6e9b 206
8f23e84c 207 if (argc == 0) {
972e6e9b
L
208 /* no more args, print pin config */
209
210 char *pin_names[GPIO_MAX + 1];
211 uint_fast8_t pin_names_width = pinnames_get(pin_names);
212
8f23e84c 213 if (pinargc == 1)
972e6e9b 214 print_pin(pinarg[0], 0, pin_names, pin_names_width);
8f23e84c
L
215 else {
216 if (printheader) {
217 if (pin_names_width > 0) {
218 if ( strlen("Name") > pin_names_width)
219 pin_names_width = strlen("Name");
220 char s[pin_names_width+1];
221 memset(s, ' ', pin_names_width);
222 s[pin_names_width] = '\0';
223 strncpy_P(s, PSTR("Name"), 4);
224 printf_P(PSTR("Pin %s Config Level Divider Frequency/Hz\n"),s);
225 memset(s, '-', pin_names_width);
226 printf_P(PSTR("----%s-----------------------------------\n"), s);
227 } else
228 printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n"
229 "--------------------------------------\n"));
230 }
231 for (uint_fast8_t i = 0; i < pinargc; i++)
972e6e9b 232 print_pin(pinarg[i], 1, pin_names, pin_names_width);
8f23e84c 233 }
972e6e9b
L
234 if (pin_names[GPIO_MAX] != NULL)
235 free(pin_names[GPIO_MAX]);
8f23e84c
L
236 return CMD_RET_SUCCESS;
237 }
238
239 /* arguments must be in pairs: pins conf */
240 if (argc % 2 != 1)
241 return CMD_RET_USAGE;
242
243 while (argc > 0) {
244 char *endp;
05994bd9 245 gpiomode_t mode = NONE;
8f23e84c
L
246 int level = 0;
247 unsigned long value = 0;
248 uint8_t hz_flag = 0;
249
250 switch (toupper(argv[optind][0])) {
251 case 'H':
252 level = 1;
253 case 'L':
254 mode = OUTPUT;
255 break;
256 case 'P':
257 mode = INPUT_PULLUP;
258 break;
259 case 'I':
260 case 'T':
261 mode = INPUT;
262 break;
263
264 default:
265 value = strtoul(argv[optind], &endp, 10);
266 switch (*endp) {
267 case 'M':
268 value *= 1000;
269 case 'K':
270 value *= 1000;
271 endp++;
272 }
273
274 if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
275 hz_flag = 1;
276 endp += 2;
277 }
278
279 if (*endp != '\0') {
280 printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]);
281 return CMD_RET_USAGE;
282 }
283
284 if (value == 0) {
285 printf_P(PSTR("invalid value: %lu \n"));
286 return CMD_RET_USAGE;
287 }
288
289 if (hz_flag) {
290 if (value > F_CPU / 2) {
291 printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
292 return CMD_RET_USAGE;
293 }
294 value = F_CPU/value;
295 }
296 mode = OUTPUT_TIMER;
297
298 }
299
300 if (mode == NONE)
301 return CMD_RET_USAGE;
302
303 for (uint_fast8_t i = 0; i < pinargc; i++) {
304 switch (mode) {
305 case OUTPUT:
05994bd9 306 gpio_write(pinarg[i], level);
8f23e84c
L
307 /* fall thru */
308 case INPUT:
309 case INPUT_PULLUP:
05994bd9 310 gpio_config(pinarg[i], mode);
8f23e84c
L
311 break;
312 case OUTPUT_TIMER:
05994bd9 313 if (gpio_clockdiv_set(pinarg[i], value) < 0) {
8f23e84c
L
314 printf_P(PSTR("Setting pin %d to %lu failed.\n"),
315 pinarg[i], value);
316 }
317 break;
318 default:
319 break;
320 }
321 }
322
323 optind++;
324 pinargc = pinarg_get(argv[optind++], pinarg);
325 argc -= 2;
326 }
327
328 return CMD_RET_SUCCESS;
329}