From d868e2f7263fb48c4b3595a535876ae9eacbd359 Mon Sep 17 00:00:00 2001 From: Alan Carvalho de Assis Date: Wed, 17 Jul 2019 12:48:39 +0200 Subject: [PATCH] apps/examples/chrono: Add chronometer apps example. --- examples/chrono/.gitignore | 12 + examples/chrono/Kconfig | 30 +++ examples/chrono/Make.defs | 39 +++ examples/chrono/Makefile | 59 +++++ examples/chrono/chrono_main.c | 474 ++++++++++++++++++++++++++++++++++ 5 files changed, 614 insertions(+) create mode 100644 examples/chrono/.gitignore create mode 100644 examples/chrono/Kconfig create mode 100644 examples/chrono/Make.defs create mode 100644 examples/chrono/Makefile create mode 100644 examples/chrono/chrono_main.c diff --git a/examples/chrono/.gitignore b/examples/chrono/.gitignore new file mode 100644 index 000000000..caa9bdef2 --- /dev/null +++ b/examples/chrono/.gitignore @@ -0,0 +1,12 @@ +/hello +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/examples/chrono/Kconfig b/examples/chrono/Kconfig new file mode 100644 index 000000000..42d1faaec --- /dev/null +++ b/examples/chrono/Kconfig @@ -0,0 +1,30 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_CHRONO + tristate "Chronometer example to use with STM32LDiscover" + default n + ---help--- + Enable the Chronometer example + +if EXAMPLES_CHRONO + +config EXAMPLES_CHRONO_PROGNAME + string "Program name" + default "chrono" + depends on BUILD_LOADABLE + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config EXAMPLES_CHRONO_PRIORITY + int "Chrono task priority" + default 100 + +config EXAMPLES_CHRONO_STACKSIZE + int "Chrono stack size" + default 2048 + +endif diff --git a/examples/chrono/Make.defs b/examples/chrono/Make.defs new file mode 100644 index 000000000..7800476f6 --- /dev/null +++ b/examples/chrono/Make.defs @@ -0,0 +1,39 @@ +############################################################################ +# apps/examples/chrono/Make.defs +# Adds selected applications to apps/ build +# +# Copyright (C) 2015 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_CHRONO),) +CONFIGURED_APPS += examples/chrono +endif diff --git a/examples/chrono/Makefile b/examples/chrono/Makefile new file mode 100644 index 000000000..c2106f44b --- /dev/null +++ b/examples/chrono/Makefile @@ -0,0 +1,59 @@ +############################################################################ +# apps/examples/chrono/Makefile +# +# Copyright (C) 2008, 2010-2013 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/Make.defs + +# Chronometer built-in application info + +CONFIG_EXAMPLES_CHRONO_PRIORITY ?= SCHED_PRIORITY_DEFAULT +CONFIG_EXAMPLES_CHRONO_STACKSIZE ?= 2048 + +APPNAME = chrono + +PRIORITY = $(CONFIG_EXAMPLES_CHRONO_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_CHRONO_STACKSIZE) + +# Chronometer Example + +ASRCS = +CSRCS = +MAINSRC = chrono_main.c + +CONFIG_EXAMPLES_CHRONO_PROGNAME ?= chrono$(EXEEXT) +PROGNAME = $(CONFIG_EXAMPLES_CHRONO_PROGNAME) + +MODULE = CONFIG_EXAMPLES_CHRONO + +include $(APPDIR)/Application.mk diff --git a/examples/chrono/chrono_main.c b/examples/chrono/chrono_main.c new file mode 100644 index 000000000..878ea4670 --- /dev/null +++ b/examples/chrono/chrono_main.c @@ -0,0 +1,474 @@ +/**************************************************************************** + * examples/chrono/chrono_main.c + * + * Copyright (C) 2008, 2011-2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BUTTON_SIGNO 13 +#define BUTTON_STACKSIZE 2048 +#define BUTTON_PRIORITY 100 +#define BUTTON_DEVPATH "/dev/buttons" + +#define SLCD_DEVNAME "/dev/slcd0" +#define SLCD_BUFSIZE 8 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* What is the current chronometer status? */ + +enum chronostate_e +{ + CHRONO_RESETED = 0, + CHRONO_RUNNING, + CHRONO_STOPPED, +}; + +/* All state information for this test is kept within the following structure + * in order create a namespace and to minimize the possibility of name + * collisions. + * + * NOTE: stream must be the first element of struct slcd_chrono_s to support + * casting between these two types. + */ + +struct slcd_chrono_s +{ + struct lib_outstream_s stream; /* Stream to use for all output */ + struct slcd_attributes_s attr; /* Size of the SLCD (rows x columns) */ + int fd; /* File descriptor or the open SLCD device */ + bool initialized; /* TRUE: Initialized */ + struct timespec ts_start; /* Store the initial time */ + struct timespec ts_end; /* Store the final time */ + int state; + + /* The I/O buffer */ + + uint8_t buffer[SLCD_BUFSIZE]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct slcd_chrono_s g_slcd; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: button_daemon + ****************************************************************************/ + +static int button_daemon(int argc, char *argv[]) +{ + FAR struct slcd_chrono_s *priv = &g_slcd; + struct btn_notify_s btnevents; + btn_buttonset_t supported; + btn_buttonset_t sample = 0; + + int ret; + int fd; + int i; + + UNUSED(i); + + printf("button_daemon: Running\n"); + + /* Open the BUTTON driver */ + + printf("button_daemon: Opening %s\n", BUTTON_DEVPATH); + fd = open(BUTTON_DEVPATH, O_RDONLY | O_NONBLOCK); + if (fd < 0) + { + int errcode = errno; + printf("button_daemon: ERROR: Failed to open %s: %d\n", + BUTTON_DEVPATH, errcode); + goto errout; + } + + /* Get the set of BUTTONs supported */ + + ret = ioctl(fd, BTNIOC_SUPPORTED, + (unsigned long)((uintptr_t)&supported)); + if (ret < 0) + { + int errcode = errno; + printf("button_daemon: ERROR: ioctl(BTNIOC_SUPPORTED) failed: %d\n", + errcode); + goto errout_with_fd; + } + + printf("button_daemon: Supported BUTTONs 0x%02x\n", + (unsigned int)supported); + + /* Define the notifications events */ + + btnevents.bn_press = supported; + btnevents.bn_release = supported; + + btnevents.bn_event.sigev_notify = SIGEV_SIGNAL; + btnevents.bn_event.sigev_signo = BUTTON_SIGNO; + + /* Register to receive a signal when buttons are pressed/released */ + + ret = ioctl(fd, BTNIOC_REGISTER, + (unsigned long)((uintptr_t)&btnevents)); + if (ret < 0) + { + int errcode = errno; + printf("button_daemon: ERROR: ioctl(BTNIOC_SUPPORTED) failed: %d\n", + errcode); + goto errout_with_fd; + } + + /* Now loop forever, waiting BUTTONs events */ + + for (; ; ) + { + struct siginfo value; + sigset_t set; + + /* Wait for a signal */ + + (void)sigemptyset(&set); + (void)sigaddset(&set, BUTTON_SIGNO); + ret = sigwaitinfo(&set, &value); + if (ret < 0) + { + int errcode = errno; + printf("button_daemon: ERROR: sigwaitinfo() failed: %d\n", errcode); + goto errout_with_fd; + } + + sample = (btn_buttonset_t)value.si_value.sival_int; + + if (priv->state == CHRONO_STOPPED) + { + (void)clock_gettime(CLOCK_MONOTONIC, &priv->ts_start); + priv->state = CHRONO_RUNNING; + } + else + { + priv->state = CHRONO_STOPPED; + } + + /* Make sure that everything is displayed */ + + fflush(stdout); + + usleep(1000); + } + +errout_with_fd: + (void)close(fd); + +errout: + + printf("button_daemon: Terminating\n"); + return EXIT_FAILURE; +} + +/**************************************************************************** + * Name: slcd_flush + ****************************************************************************/ + +static int slcd_flush(FAR struct lib_outstream_s *stream) +{ + FAR struct slcd_chrono_s *priv = (FAR struct slcd_chrono_s *)stream; + FAR const uint8_t *buffer; + ssize_t nwritten; + ssize_t remaining; + + /* Loop until all bytes were written (handling both partial and interrupted + * writes). + */ + + remaining = stream->nput; + buffer = priv->buffer; + + while (remaining > 0) + { + nwritten = write(priv->fd, buffer, remaining); + if (nwritten < 0) + { + int errcode = errno; + printf("write failed: %d\n", errcode); + + if (errcode != EINTR) + { + exit(EXIT_FAILURE); + } + } + else + { + remaining -= nwritten; + buffer += nwritten; + } + } + + /* Reset the stream */ + + stream->nput = 0; + return OK; +} + +/**************************************************************************** + * Name: slcd_putc + ****************************************************************************/ + +static void slcd_putc(FAR struct lib_outstream_s *stream, int ch) +{ + FAR struct slcd_chrono_s *priv = (FAR struct slcd_chrono_s *)stream; + + /* Write the character to the buffer */ + + priv->buffer[stream->nput] = ch; + stream->nput++; + priv->buffer[stream->nput] = '\0'; + + /* If the buffer is full, flush it */ + + if (stream->nput >= CONFIG_EXAMPLES_SLCD_BUFSIZE) + { + (void)slcd_flush(stream); + } +} + +/**************************************************************************** + * Name: slcd_puts + ****************************************************************************/ + +static void slcd_puts(FAR struct lib_outstream_s *outstream, + FAR const char *str) +{ + for (; *str; str++) + { + slcd_put((int)*str, outstream); + } +} + +/**************************************************************************** + * chrono_main + ****************************************************************************/ + +#if defined(BUILD_MODULE) +int main(int argc, FAR char *argv[]) +#else +int chrono_main(int argc, char *argv[]) +#endif +{ + FAR struct slcd_chrono_s *priv = &g_slcd; + FAR char str[8] = "00:00.0"; + int fd; + int ret; + long sec; + long min; + + /* Create a thread to wait for the button events */ + + ret = task_create("button_daemon", BUTTON_PRIORITY, + BUTTON_STACKSIZE, button_daemon, NULL); + if (ret < 0) + { + int errcode = errno; + printf("buttons_main: ERROR: Failed to start button_daemon: %d\n", + errcode); + return EXIT_FAILURE; + } + + /* Open the SLCD device */ + + printf("Opening %s for read/write access\n", SLCD_DEVNAME); + + fd = open(SLCD_DEVNAME, O_RDWR); + if (fd < 0) + { + printf("Failed to open %s: %d\n", CONFIG_EXAMPLES_SLCD_DEVNAME, errno); + goto errout; + } + + /* Get the attributes of the SCLD device */ + + ret = ioctl(fd, SLCDIOC_GETATTRIBUTES, (unsigned long)&priv->attr); + if (ret < 0) + { + printf("ioctl(SLCDIOC_GETATTRIBUTES) failed: %d\n", errno); + goto errout_with_fd; + } + + /* Are we already initialized? */ + + if (!priv->initialized) + { + /* Initialize the output stream */ + + memset(priv, 0, sizeof(struct slcd_chrono_s)); + priv->stream.put = slcd_putc; +#ifdef CONFIG_STDIO_LINEBUFFER + priv->stream.flush = slcd_flush; +#endif + + /* Get the attributes of the SCLD device */ + + ret = ioctl(fd, SLCDIOC_GETATTRIBUTES, (unsigned long)&priv->attr); + if (ret < 0) + { + printf("ioctl(SLCDIOC_GETATTRIBUTES) failed: %d\n", errno); + goto errout_with_fd; + } + + printf("Attributes:\n"); + printf(" rows: %d columns: %d nbars: %d\n", + priv->attr.nrows, priv->attr.ncolumns, priv->attr.nbars); + printf(" max contrast: %d max brightness: %d\n", + priv->attr.maxcontrast, priv->attr.maxbrightness); + + /* Home the cursor and clear the display */ + + printf("Clear screen\n"); + slcd_encode(SLCDCODE_CLEAR, 0, &priv->stream); + slcd_flush(&priv->stream); + + priv->initialized = true; + } + + /* Save the file descriptor in a place where slcd_flush can find it */ + + priv->fd = fd; + + /* Set the cursor to the beginning of the current row by homing the cursor + * then going down as necessary, and erase to the end of the line. + */ + + slcd_encode(SLCDCODE_HOME, 0, &priv->stream); + slcd_encode(SLCDCODE_ERASEEOL, 0, &priv->stream); + + priv->state = CHRONO_RESETED; + + for (; ; ) + { + /* If the device is reseted, show 00.. and assume it is initial time */ + + if (priv->state == CHRONO_RESETED) + { + /* Copy the initial value */ + + strncpy(str, "00:00.0", 7); + + /* Print the initial reset value */ + + slcd_puts(&priv->stream, str); + slcd_flush(&priv->stream); + + /* Move to stopped state to avoid wasting time here */ + + priv->state = CHRONO_STOPPED; + } + + /* If the device is stopped nothing to do here */ + + if (priv->state == CHRONO_STOPPED) + { + } + + /* If the chronometer is running, get the elapsed time and how it */ + + if (priv->state == CHRONO_RUNNING) + { + /* Get the current time */ + + (void)clock_gettime(CLOCK_MONOTONIC, &priv->ts_end); + + /* How many seconds passed from initial time? */ + + sec = priv->ts_end.tv_sec - priv->ts_start.tv_sec; + + /* Get the amount of minutes */ + + min = sec / 60; + + /* Get the remaining seconds */ + + sec = sec % 60; + + sprintf(str, "%02d:%02d:%01d", min, sec, + (priv->ts_end.tv_nsec / 100000000)); + + /* Print it into LCD */ + + slcd_encode(SLCDCODE_HOME, 0, &priv->stream); + slcd_puts(&priv->stream, str); + slcd_flush(&priv->stream); + } + + /* usleep(1000); */ + } + + /* Normal exit */ + + close(fd); + return 0; + +errout_with_fd: + close(priv->fd); +errout: + priv->initialized = false; + exit(EXIT_FAILURE); +}