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