From 1e2358f5bfdb312a084d40766d4b2e95641b8544 Mon Sep 17 00:00:00 2001 From: Javier Viguera Date: Mon, 11 Sep 2017 12:34:44 +0200 Subject: [PATCH] dey-examples: add libdigiapix GPIO example https://jira.digi.com/browse/DEL-4795 Signed-off-by: Javier Viguera --- apix-gpio-example/Makefile | 34 ++++++ apix-gpio-example/README.md | 49 +++++++++ apix-gpio-example/main.c | 205 ++++++++++++++++++++++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 apix-gpio-example/Makefile create mode 100644 apix-gpio-example/README.md create mode 100644 apix-gpio-example/main.c diff --git a/apix-gpio-example/Makefile b/apix-gpio-example/Makefile new file mode 100644 index 0000000..b3fd796 --- /dev/null +++ b/apix-gpio-example/Makefile @@ -0,0 +1,34 @@ +# +# Copyright 2017, Digi International Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. +# + +BINARY := apix-gpio-example + +CFLAGS += -Wall -O2 + +CFLAGS += $(shell pkg-config --cflags libdigiapix) +LDLIBS += $(shell pkg-config --libs libdigiapix) + +$(BINARY): main.o + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +.PHONY: install +install: $(BINARY) + install -d $(DESTDIR)/usr/bin + install -m 0755 $^ $(DESTDIR)/usr/bin/ + +.PHONY: clean +clean: + -rm -f *.o $(BINARY) diff --git a/apix-gpio-example/README.md b/apix-gpio-example/README.md new file mode 100644 index 0000000..1ff8d93 --- /dev/null +++ b/apix-gpio-example/README.md @@ -0,0 +1,49 @@ +Digi APIX GPIO Example Application +================================== +The example application uses a gpio as input (e.g. a user button) and another +one as output (e.g. a user led). The application toggles the output GPIO +whenever an interrupt is generated in the input GPIO. + +Running the application +----------------------- +Once the binary is in the target, launch the application: + +``` +root@ccimx6ulstarter:~# ./apix-gpio-example +Example application using libdigiapix GPIO support + +Usage: apix-gpio-example + + Push-button GPIO number or alias + LED GPIO number or alias + +Aliases for GPIO numbers can be configured in the library config file +``` + +Compiling the application +------------------------- +This example can be compiled using a Digi Embedded Yocto based toolchain. Make +sure to source the corresponding toolchain of the platform you are using, e.g: + +``` +$ . /environment-setup-cortexa7hf-neon-dey-linux-gnueabi +$ make +``` + +More information about [Digi Embedded Yocto](https://github.com/digi-embedded/meta-digi). + +License +------- +Copyright 2017, Digi International Inc. + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/apix-gpio-example/main.c b/apix-gpio-example/main.c new file mode 100644 index 0000000..c3f4422 --- /dev/null +++ b/apix-gpio-example/main.c @@ -0,0 +1,205 @@ +/* + * Copyright 2017, Digi International Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TEST_LOOPS 6 + +static gpio_t *gpio_input; +static gpio_t *gpio_output; + +struct gpio_interrupt_cb_data { + gpio_t *gpio; + gpio_value_t value; + int remaining_loops; +}; + +/* + * Function: usage_and_exit + * Description: show usage information and exit with 'exitval' return value + */ +static void usage_and_exit(char *name, int exitval) +{ + fprintf(stdout, + "Example application using libdigiapix GPIO support\n" + "\n" + "Usage: %s \n\n" + " Push-button GPIO number or alias\n" + " LED GPIO number or alias\n" + "\n" + "Aliases for GPIO numbers can be configured in the library config file\n" + "\n", name); + + exit(exitval); +} + +static void cleanup(void) +{ + /* Stop the interrupt handler thread */ + gpio_stop_wait_interrupt(gpio_input); + + /* Free gpios */ + gpio_free(gpio_input); + gpio_free(gpio_output); +} + +static void sigaction_handler(int signum) +{ + /* 'atexit' executes the cleanup function */ + exit(EXIT_FAILURE); +} + +static void register_signals(void) +{ + struct sigaction action; + + action.sa_handler = sigaction_handler; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +} + +static int gpio_interrupt_cb(void *arg) +{ + struct gpio_interrupt_cb_data *data = arg; + + printf("Input GPIO interrupt detected; toggling output GPIO\n"); + + /* Toggle output GPIO */ + data->value = data->value ? GPIO_LOW : GPIO_HIGH; + gpio_set_value(data->gpio, data->value); + + /* Decrease remaining loops */ + data->remaining_loops -= 1; + + return 0; +} + +static int parse_argument(char *argv) +{ + char *endptr; + long value; + + errno = 0; + value = strtol(argv, &endptr, 10); + + if ((errno == ERANGE && (value == LONG_MAX || value == LONG_MIN)) + || (errno != 0 && value == 0)) + return -1; + + if (endptr == argv) + return gpio_get_kernel_number(endptr); + + return value; +} + +int main(int argc, char *argv[]) +{ + int button, led, i; + gpio_value_t output_value = GPIO_LOW; /* Should match the GPIO request mode */ + struct gpio_interrupt_cb_data cb_data; + char *name = basename(argv[0]); + + /* Check input parameters */ + if (argc != 3) + usage_and_exit(name, EXIT_FAILURE); + + /* Parse command line arguments */ + button = parse_argument(argv[1]); + led = parse_argument(argv[2]); + if (button < 0 || led < 0) { + printf("Unable to parse button and led GPIOs\n"); + return EXIT_FAILURE; + } + + /* Register signals and exit cleanup function */ + atexit(cleanup); + register_signals(); + + /* Request input GPIO */ + gpio_input = + gpio_request((unsigned)button, GPIO_IRQ_EDGE_RISING, + REQUEST_SHARED); + if (!gpio_input) { + printf("Failed to initialize input GPIO\n"); + return EXIT_FAILURE; + } + + /* Request output GPIO */ + gpio_output = + gpio_request((unsigned)led, GPIO_OUTPUT_LOW, REQUEST_SHARED); + if (!gpio_output) { + printf("Failed to initialize output GPIO\n"); + return EXIT_FAILURE; + } + + /* Configure input GPIO to active HIGH */ + gpio_set_active_mode(gpio_input, GPIO_ACTIVE_HIGH); + + /* + * Test blocking interrupt mode + */ + printf("[INFO] Testing interrupt blocking mode\n"); + printf("Press the button (for %d events):\n", TEST_LOOPS); + for (i = 0; i < TEST_LOOPS; i++) { + if (gpio_wait_interrupt(gpio_input, -1) == GPIO_IRQ_ERROR_NONE) { + printf("Press %d; toggling output GPIO\n", i + 1); + output_value = output_value ? GPIO_LOW : GPIO_HIGH; + gpio_set_value(gpio_output, output_value); + } + } + + /* + * Test async mode + */ + printf("[INFO] Testing interrupt asynchronous mode\n"); + + /* Initialize data to be passed to the interrupt handler */ + cb_data.gpio = gpio_output; + cb_data.value = output_value; + cb_data.remaining_loops = TEST_LOOPS; + + printf + ("Parent process will wait until %d interrupts have been detected\n", + TEST_LOOPS); + + if (gpio_start_wait_interrupt(gpio_input, &gpio_interrupt_cb, &cb_data) + != EXIT_SUCCESS) { + printf("Failed to start interrupt handler thread\n"); + return EXIT_FAILURE; + } + + /* Parent process */ + while (cb_data.remaining_loops > 0) { + printf("Parent process: waiting ...\n"); + sleep(5); + } + printf("Parent process: no remaining interrupts. Test finished\n"); + + /* 'atexit' executes the cleanup function */ + return EXIT_SUCCESS; +}