From 704a82aaa6cff3d4a9be0f98e38f28a0a911fc9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beat=20K=C3=BCng?= Date: Thu, 9 Jul 2020 13:18:50 +0200 Subject: [PATCH] gpio: extend support for /dev/gp* GPIO's Note that there's a small CLI interface change. --- src/systemcmds/gpio/gpio.cpp | 163 +++++++++++++++++++++++++++++------ 1 file changed, 137 insertions(+), 26 deletions(-) diff --git a/src/systemcmds/gpio/gpio.cpp b/src/systemcmds/gpio/gpio.cpp index e70c31a934..7a67dd4b09 100644 --- a/src/systemcmds/gpio/gpio.cpp +++ b/src/systemcmds/gpio/gpio.cpp @@ -42,43 +42,152 @@ #include #include +#include +#include + static void usage(const char *reason); +static int handle_board_ports(bool is_read, int argc, char *argv[]); +static int handle_device_ports(bool is_read, int argc, char *argv[]); extern "C" __EXPORT int gpio_main(int argc, char *argv[]) { - if (argc < 4) { + if (argc < 3) { usage("not enough arguments"); return -1; } const char *command = argv[1]; bool is_read = false; - uint32_t mask = 0; if (strcmp(command, "read") == 0) { is_read = true; - mask |= GPIO_INPUT; } else if (strcmp(command, "write") == 0) { - if (argc < 5) { + if (argc < 4) { usage("not enough arguments"); return -1; } - mask |= GPIO_OUTPUT; - } else { usage("command not read or write"); return -1; } - const char *port_string = argv[2]; + if (argv[2][0] == '/') { + return handle_device_ports(is_read, argc, argv); - if (strlen(port_string) != 1) { - usage("port not a single character"); + } else { + return handle_board_ports(is_read, argc, argv); + } +} + +int handle_device_ports(bool is_read, int argc, char *argv[]) +{ +#ifdef CONFIG_DEV_GPIO + const char *device = argv[2]; + int fd = open(device, O_RDWR); + + if (fd < 0) { + usage("Opening the device failed"); + return -1; } + char *end; + + if (is_read) { + gpio_pintype_e pin_type = GPIO_INPUT_PIN; + + if (argc >= 4) { + const char *extra = argv[3]; + + if (strcasecmp(extra, "PULLUP") == 0) { + pin_type = GPIO_INPUT_PIN_PULLUP; + + } else if (strcasecmp(extra, "PULLDOWN") == 0) { + pin_type = GPIO_INPUT_PIN_PULLDOWN; + + } else { + usage("extra read argument not PULLUP or PULLDOWN"); + goto exit_failure; + } + } + + int ret = ioctl(fd, GPIOC_SETPINTYPE, pin_type); + + if (ret != 0) { + PX4_ERR("ioctl GPIOC_SETPINTYPE failed: %i", ret); + goto exit_failure; + } + + bool value; + ret = ioctl(fd, GPIOC_READ, (long)&value); + + if (ret != 0) { + PX4_ERR("ioctl GPIOC_READ failed: %i", ret); + goto exit_failure; + } + + printf("%d OK\n", (int)value); + + } else { + gpio_pintype_e pin_type = GPIO_OUTPUT_PIN; + + int32_t value = strtol(argv[3], &end, 10); + + if (errno != 0 || *end != '\0' || (value != 0 && value != 1)) { + usage("value not 0 or 1"); + goto exit_failure; + } + + if (argc >= 5) { + const char *extra = argv[4]; + + if (strcasecmp(extra, "PUSHPULL") == 0) { + pin_type = GPIO_OUTPUT_PIN; + + } else if (strcasecmp(extra, "OPENDRAIN") == 0) { + pin_type = GPIO_OUTPUT_PIN_OPENDRAIN; + + } else { + usage("extra write argument not PUSHPULL or OPENDRAIN"); + goto exit_failure; + } + } + + int ret = ioctl(fd, GPIOC_SETPINTYPE, pin_type); + + if (ret != 0) { + PX4_ERR("ioctl GPIOC_SETPINTYPE failed: %i", ret); + goto exit_failure; + } + + ret = ioctl(fd, GPIOC_WRITE, value); + + if (ret != 0) { + PX4_ERR("ioctl GPIOC_WRITE failed: %i", ret); + goto exit_failure; + } + + printf("OK\n"); + } + + close(fd); + return 0; + +exit_failure: + close(fd); + return -1; +#else + usage("not supported"); + return -1; +#endif +} + +int handle_board_ports(bool is_read, int argc, char *argv[]) +{ + const char *port_string = argv[2]; char port = port_string[0]; + uint32_t mask = is_read ? GPIO_INPUT : GPIO_OUTPUT; if ('A' <= port && port <= 'K') { mask |= ((port - 'A') << GPIO_PORT_SHIFT) & GPIO_PORT_MASK; @@ -92,7 +201,7 @@ extern "C" __EXPORT int gpio_main(int argc, char *argv[]) } char *end; - int32_t pin = strtol(argv[3], &end, 10); + int32_t pin = strtol(argv[2] + 1, &end, 10); if (errno == 0 && *end == '\0' && 0 <= pin && pin <= 15) { mask |= (pin << GPIO_PIN_SHIFT) & GPIO_PIN_MASK;; @@ -102,6 +211,8 @@ extern "C" __EXPORT int gpio_main(int argc, char *argv[]) return -1; } + PX4_DEBUG("port=%c, pin=%i", port, pin); + bool matches_default_config = false; #if defined(PX4_GPIO_INIT_LIST) const uint32_t default_gpios[] = PX4_GPIO_INIT_LIST; @@ -126,8 +237,8 @@ extern "C" __EXPORT int gpio_main(int argc, char *argv[]) } if (is_read) { - if (argc >= 5) { - const char *extra = argv[4]; + if (argc >= 4) { + const char *extra = argv[3]; if (strcasecmp(extra, "PULLUP") == 0) { mask |= GPIO_PULLUP; @@ -135,7 +246,7 @@ extern "C" __EXPORT int gpio_main(int argc, char *argv[]) } else if (strcasecmp(extra, "PULLDOWN") == 0) { mask |= GPIO_PULLDOWN; - } else if (argc == 5 && !force_apply) { + } else if (argc == 4 && !force_apply) { usage("extra read argument not PULLUP or PULLDOWN"); return -1; } @@ -146,15 +257,15 @@ extern "C" __EXPORT int gpio_main(int argc, char *argv[]) printf("%d OK\n", value); } else { - int32_t value = strtol(argv[4], &end, 10); + int32_t value = strtol(argv[3], &end, 10); if (errno != 0 || *end != '\0' || (value != 0 && value != 1)) { usage("value not 0 or 1"); return -1; } - if (argc >= 6) { - const char *extra = argv[5]; + if (argc >= 5) { + const char *extra = argv[4]; if (strcasecmp(extra, "PUSHPULL") == 0) { mask |= GPIO_PUSHPULL; @@ -162,7 +273,7 @@ extern "C" __EXPORT int gpio_main(int argc, char *argv[]) } else if (strcasecmp(extra, "OPENDRAIN") == 0) { mask |= GPIO_OPENDRAIN; - } else if (argc == 6 && !force_apply) { + } else if (argc == 5 && !force_apply) { usage("extra write argument not PUSHPULL or OPENDRAIN"); return -1; } @@ -189,32 +300,32 @@ void usage(const char *reason) ### Description This command is used to read and write GPIOs -gpio read [PULLDOWN|PULLUP] [--force] -gpio write [PUSHPULL|OPENDRAIN] [--force] +gpio read / [PULLDOWN|PULLUP] [--force] +gpio write / [PUSHPULL|OPENDRAIN] [--force] ### Examples Read the value on port H pin 4 configured as pullup, and it is high -$ gpio_test read H 4 PU +$ gpio read H4 PULLUP 1 OK Set the output value on Port E pin 7 to high -$ gpio_test write E 7 1 --force -OK +$ gpio write E7 1 --force + +Set the output value on device /dev/gpin1 to high +$ gpio write /dev/gpin1 1 )DESCR_STR"); - PRINT_MODULE_DESCRIPTION("This command is used to read and write GPIOs."); - PRINT_MODULE_USAGE_NAME_SIMPLE("gpio", "command"); PRINT_MODULE_USAGE_COMMAND("read"); - PRINT_MODULE_USAGE_ARG(" ", "GPIO port and pin", false); + PRINT_MODULE_USAGE_ARG("/", "GPIO port and pin or device", false); PRINT_MODULE_USAGE_ARG("PULLDOWN|PULLUP", "Pulldown/Pullup", true); PRINT_MODULE_USAGE_ARG("--force", "Force (ignore board gpio list)", true); PRINT_MODULE_USAGE_COMMAND("write"); PRINT_MODULE_USAGE_ARG(" ", "GPIO port and pin", false); PRINT_MODULE_USAGE_ARG("", "Value to write", false); - PRINT_MODULE_USAGE_ARG("PULLDOWN|PULLUP", "Pulldown/Pullup", true); + PRINT_MODULE_USAGE_ARG("PUSHPULL|OPENDRAIN", "Pushpull/Opendrain", true); PRINT_MODULE_USAGE_ARG("--force", "Force (ignore board gpio list)", true); }