summaryrefslogtreecommitdiff
path: root/avr/cmd_pin.c
diff options
context:
space:
mode:
Diffstat (limited to 'avr/cmd_pin.c')
-rw-r--r--avr/cmd_pin.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/avr/cmd_pin.c b/avr/cmd_pin.c
new file mode 100644
index 0000000..b46b853
--- /dev/null
+++ b/avr/cmd_pin.c
@@ -0,0 +1,329 @@
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <avr/pgmspace.h>
+
+#include "command.h"
+#include "print-utils.h"
+#include "getopt-min.h"
+#include "env.h"
+#include "pin.h"
+//#include "debug.h"
+
+
+
+static const int namestr = PIN_MAX;
+static char *pin_names[PIN_MAX+1];
+static uint_least8_t pin_names_width;
+
+static void pinnames_get(void)
+{
+ static const FLASH char delim1[] = {":= "};
+ static const FLASH char delim2[] = {", "};
+ char *lp;
+ char *ptr;
+ uint_fast8_t i;
+
+ if (pin_names[namestr] != NULL)
+ free(pin_names[namestr]);
+ memset(pin_names, 0, sizeof(pin_names));
+ pin_names_width = 0;
+
+ if ((lp = getenv(PSTR(ENV_PINALIAS))) != NULL) {
+ pin_names[namestr] = strdup(lp);
+ ptr = strtok_P(pin_names[namestr], delim1);
+ while (ptr != NULL) {
+ if (((i = strtoul(ptr, &lp, 10)) < PIN_MAX) &&
+ lp != ptr &&
+ (ptr = strtok_P(NULL, delim2)) != NULL ) {
+ pin_names[i] = ptr;
+ ptr = strtok_P(NULL, delim1);
+ }
+ }
+
+ for (i = 0; i < PIN_MAX; i++)
+ if (strlen(pin_names[i]) > pin_names_width)
+ pin_names_width = strlen(pin_names[i]);
+ }
+}
+
+
+static size_t xstrlen(char *s)
+{
+ if (s == NULL)
+ return 0;
+ else
+ return strlen(s);
+}
+
+static const FLASH char * const FLASH pinconf_str[] = {
+ FSTR("?"),
+ FSTR("Input"),
+ FSTR("Pullup"),
+ FSTR("Output"),
+ FSTR("Clock"),
+ };
+
+static const FLASH char * const FLASH pinlevel_str[] = {
+ FSTR("Low"),
+ FSTR("High"),
+ FSTR(""),
+ };
+
+static int print_pin(int pin, int multi)
+{
+ int pinconf;
+ const FLASH char *levelp;
+ long div;
+
+ pinconf = pin_config_get(pin);
+ if (pinconf == OUTPUT_TIMER) {
+ div = pin_clockdiv_get(pin);
+ levelp = pinlevel_str[2];
+ } else
+ levelp = pinlevel_str[pin_read(pin)];
+
+ if (multi) {
+ printf_P(PSTR("%3d "), pin);
+ if (pin_names_width) {
+ printf_P(PSTR("%s "), pin_names[pin]);
+ print_blanks(pin_names_width - xstrlen(pin_names[pin]));
+ }
+ my_puts_P(pinconf_str[pinconf]);
+ print_blanks(7 - strlen_P(pinconf_str[pinconf]));
+ my_puts_P(levelp);
+ print_blanks(5 - strlen_P(levelp));
+ if (pinconf == OUTPUT_TIMER)
+ printf_P(PSTR("%8ld %8ld"),
+ div, F_CPU/div);
+ } else {
+ printf_P(PSTR("%d: \"%s\", "), pin, pin_names[pin] ? pin_names[pin] : 0);
+ my_puts_P(pinconf_str[pinconf]);
+ printf_P(PSTR(", "));
+ my_puts_P(levelp);
+
+ if (pinconf == OUTPUT_TIMER)
+ printf_P(PSTR("divide by %ld (%ldHz)"),
+ div, F_CPU/div);
+ }
+ printf_P(PSTR("\n"));
+
+ return 0;
+}
+
+static int_fast8_t pinarg_insert(int pin, uint_fast8_t count, uint_fast8_t pinarg[])
+{
+ uint_fast8_t pos;
+
+ if (pin < 0 || pin >= PIN_MAX)
+ return -1;
+
+ for (pos = 0; pos < count; pos++) {
+ if (pin == pinarg[pos])
+ return 0;
+ if (pin < pinarg[pos])
+ break;
+ }
+ for (uint_fast8_t i = count-1; i == pos ; i--)
+ pinarg[i+1] = pinarg[i];
+ pinarg[pos] = pin;
+
+ return 1;
+}
+
+static uint_fast8_t pinarg_get(char * arg, uint_fast8_t pinarg[])
+{
+ char *endp;
+ uint_fast8_t pin1;
+ int_fast8_t rc;
+ uint_fast8_t count = 0;
+
+ while (1) {
+ pin1 = strtoul(arg, &endp, 10);
+ if (endp != arg && *endp == '-') {
+ arg = endp+1;
+ uint_fast8_t pin2 = (int) strtoul(arg, &endp, 10);
+ if (pin1 < pin2)
+ for (; pin1 < pin2; pin1++)
+ if ((rc = pinarg_insert(pin1, count, pinarg)) >= 0)
+ count += rc;
+ else
+ return 0;
+ else
+ return 0;
+ }
+ if (endp != arg) {
+ if ((*endp == ',' || *endp == '\0') &&
+ (rc = pinarg_insert(pin1, count, pinarg)) >= 0) {
+ count += rc;
+ if (*endp == '\0')
+ return count;
+ } else
+ return 0;
+ } else
+ return 0;
+
+ arg = endp+1;
+ }
+}
+
+
+command_ret_t do_pin(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ char printheader = 1;
+ uint_fast8_t pinarg[PIN_MAX];
+ uint_fast8_t pinargc;
+
+ (void) cmdtp; (void) flag;
+
+ /* reset getopt() */
+ optind = 1;
+
+ int opt;
+ while ((opt = getopt(argc, argv, PSTR("s"))) != -1) {
+ switch (opt) {
+ case 's':
+ printheader = 0;
+ break;
+ default: /* '?' */
+ return CMD_RET_USAGE;
+ }
+ }
+
+ /* remaining arguments */
+ argc -= optind;
+
+ pinnames_get();
+
+ if (argc == 0) {
+ /* print cofig of all pins */
+ for (pinargc = 0; pinargc < PIN_MAX; pinargc++)
+ pinarg[pinargc] = pinargc;
+ } else {
+ /* get first arg */
+ pinargc = pinarg_get(argv[optind++], pinarg);
+ if (pinargc == 0)
+ return CMD_RET_USAGE;
+ else
+ argc--;
+ }
+
+ if (argc == 0) {
+ /* no more args, print config */
+ if (pinargc == 1)
+ print_pin(pinarg[0], 0);
+ else {
+ if (printheader) {
+ if (pin_names_width > 0) {
+ if ( strlen("Name") > pin_names_width)
+ pin_names_width = strlen("Name");
+ char s[pin_names_width+1];
+ memset(s, ' ', pin_names_width);
+ s[pin_names_width] = '\0';
+ strncpy_P(s, PSTR("Name"), 4);
+ printf_P(PSTR("Pin %s Config Level Divider Frequency/Hz\n"),s);
+ memset(s, '-', pin_names_width);
+ printf_P(PSTR("----%s-----------------------------------\n"), s);
+ } else
+ printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n"
+ "--------------------------------------\n"));
+ }
+ for (uint_fast8_t i = 0; i < pinargc; i++)
+ print_pin(pinarg[i], 1);
+ }
+ return CMD_RET_SUCCESS;
+ }
+
+ /* arguments must be in pairs: pins conf */
+ if (argc % 2 != 1)
+ return CMD_RET_USAGE;
+
+ while (argc > 0) {
+ char *endp;
+ pinmode_t mode = NONE;
+ int level = 0;
+ unsigned long value = 0;
+ uint8_t hz_flag = 0;
+
+ switch (toupper(argv[optind][0])) {
+ case 'H':
+ level = 1;
+ case 'L':
+ mode = OUTPUT;
+ break;
+ case 'P':
+ mode = INPUT_PULLUP;
+ break;
+ case 'I':
+ case 'T':
+ mode = INPUT;
+ break;
+
+ default:
+ value = strtoul(argv[optind], &endp, 10);
+ switch (*endp) {
+ case 'M':
+ value *= 1000;
+ case 'K':
+ value *= 1000;
+ endp++;
+ }
+
+ if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
+ hz_flag = 1;
+ endp += 2;
+ }
+
+ if (*endp != '\0') {
+ printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]);
+ return CMD_RET_USAGE;
+ }
+
+ if (value == 0) {
+ printf_P(PSTR("invalid value: %lu \n"));
+ return CMD_RET_USAGE;
+ }
+
+ if (hz_flag) {
+ if (value > F_CPU / 2) {
+ printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
+ return CMD_RET_USAGE;
+ }
+ value = F_CPU/value;
+ }
+ mode = OUTPUT_TIMER;
+
+ }
+
+ if (mode == NONE)
+ return CMD_RET_USAGE;
+
+ for (uint_fast8_t i = 0; i < pinargc; i++) {
+ switch (mode) {
+ case OUTPUT:
+ pin_write(pinarg[i], level);
+ /* fall thru */
+ case INPUT:
+ case INPUT_PULLUP:
+ pin_config(pinarg[i], mode);
+ break;
+ case OUTPUT_TIMER:
+ if (pin_clockdiv_set(pinarg[i], value) < 0) {
+ printf_P(PSTR("Setting pin %d to %lu failed.\n"),
+ pinarg[i], value);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ optind++;
+ pinargc = pinarg_get(argv[optind++], pinarg);
+ argc -= 2;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+