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