diff --git a/ChangeLog b/ChangeLog index a5856e50f9..1de3de5f0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2450,4 +2450,7 @@ * fs/fat/fs_fatfs.c: Fix and error in the FAT statfs() implementation that was causing some block counts to be reported incorrectly (reported by David Sidrane). + * drivers/ramlog.c: Add a character driver that can substitute + for /dev/console and or be used for logging debug output when there + is no serial port available (such as when a telnet console is used). diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 51ac872aa2..c604b9dad4 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@
Last Updated: February 4, 2012
+Last Updated: February 9, 2012
-
+
nuttx-6.15 2012-xx-xx Gregory Nutt <gnutt@nuttx.org> + * arch/arm/src/stm32/stm32_pwm.c: Pulse count was limited to 128; now is + (essentially) unlimited. + * configs/stm3240g-eval/include/board.h: Input frequences wrong for all but + one APB2 timer. + * arch/mips/src/pic32mx/pic32mx-ethernet.c: The PIC32 Ethernet driver is + code complete, but still untested. + * confgs/sim/*/Make.defs and arch/sim/src/Makefile: Add support for building + a 32-bit executable on a 64-bit Linux target. + * configs/sure-pic32mx/src/up_leds.c: Correct GPIOs used for LEDs. The wrong + pins were being used. + * arch/arm/src/stm32/chip/stm32f10xxx_gpio.h: Correct offset to one AFIO EXICR + register. + * arch/arm/src/lpc17xx/lpc17_can.c: Added "advanced" configuration options + to specify the CAN TSEG1 and TSEG2 clock counts specifically. + * include/nuttx/can.h and drivers/can.c: Add support for extended (29-bit) + CAN IDs. + * arch/arm/src/lpc17xx/lpc17_can.c: Add support for extended (29-bit) CAN IDs. + * arch/arm/src/stm32/stm32_can.c: Add support for extended (29-bit) CAN IDs. + * include/nuttx/power/pm.h: Move include/nuttx/pm.h into a sub-directory named + power. + * drivers/power: Rename the drivers/pm directory to power + * include/power/battery.h and drivers/battery.c: Add the interface definitions + for an upper and lower half battery driver. Add the implementation of the + common upper half battery driver. + * drivers/power/max1704x.c: Add a driver for MAX17040x battery "fuel guage" + * arch/arm/src/stm32/stm32_i2c.c: Add support for I2C3 + * drivers/usbdev/: Lots of name changes: cdc_serial->cdcacm, usbstrg->usbmsc, + usbser->pl2303 + * drivers/usbdev/composite: Fleshed out support for a composite USB device. + * drivers/stm3210e-eval/composite and drivers/stm3210e-eval/src/up_composite.c: + Add a configuration test the USB composite device. + * include/nuttx/usb/usb.h, drivers/usbdev/composite_descriptors.c, and + drivers/usbdev/cdcacm_descriptors.c: Add support for the USB Interface + Association Descriptor (IAD) + * arch/arm/src/stm32/stm32_i2c.c: Correct a typo in STM32 I2C3 support + (submitted by Mike Smith) + * arch/*/src/Makefile: Candidate solution for dependency issue in the board + sub-directory: By making libboard.a a "phony" target, libboard.a should + always rebuilt (the end result is worth the small increase in build time) + (submitted by Mike Smith). + * include/net/psock.h: Added a new low level socket interface that allows the + OS to use the socket interface without having a socket descriptor. + * include/net/psock.h: Removed psock.h. The new interfaces are moved into + nuttx/net.h which already has similar logic. + * include/nuttx/usb/usb.h: Can't use 'class' as a field name in USB structures. + This upsets C++ if usb.h is included. 'class' -> 'classid' in this header + file and all places that referenced 'class' + * drivers/usbdev/usbmsc.c: Fixed some backward conditional compilation. + * sched/on_exit.c: Add support for the on_exit() function., + * sched/exit.c, task_exithook.c, task_delete.c, sched_releasetcb.c: Move + the logic that closes file descriptors sooner in the task shutdown sequence. + When drivers are closed, they may need to do things that require a fully + up-and-running task. Some things cannot be done later when the task is + crippled. + * lib/dirent: Moved readdir_r() and telldir() from lib/misc to this new + directory where they belong. + * lib/termios. Implemented tcsetattr() and tcgetattr(). + * lib/stdio/lib_fgets.c: The old fgets includes some terminal related + functionality: It handles VT-100 commands, includes a command line editor + and echo characters back to the terminal. This old, overloaded fgets() + was renamed readline() and moved to apps/system/readline. The version + of fgets() in lib/stdio was them simplified and stripped down so that it + *only* gets a string -- as its description implies. + * arch/arm/src/lpc214x/lpc214x_usbdev.c: Add corrections suggested by + David Hewson many, many months ago. + * configs/mcu123-lpc214x/composite and configs/mcu123-lpc214x/src/up_composite.c: + Add a configuration to test the USB composite device. + * configs/stm3240g-eval/telnetd: Add a configuration for testing the + Telnet daemon. + * configs/stm3240g-eval/nsh2: This is another NSH configuration. It differs + from the original nsh configuration because it does not have an RS-232 + console (only a Telnet console) and SDIO is enabled. This configuration is + required because the STM3240G-EVAL board cannot simultaneously support + RS-232 and SDIO due to pin conflicts. + * lib/string/lib_strcasestr.c: Add strcasestr(). + * lib/stdio/lib_avsprintf.c: Add avsprintf(). + * lib/net/lib_inetntop.c: Add inet_ntop(). + * lib/net/lib_inetpton.c: Add inet_pton(). + * include/pthread.h: Correct PTHREAD_MUTEX_INITIALIZER. + * fs/fat/fs_fatfs.c: Fix and error in the FAT statfs() implementation that + was causing some block counts to be reported incorrectly (reported by + David Sidrane). + apps-6.15 2012-xx-xx Gregory Nutt <gnutt@nuttx.org> -pascal-3.1 2012-xx-xx Gregory Nutt <gnutt@nuttx.org> + * apps/nshlib/nsh_serial.c and nsh_usbdev.c: If NuttX is configured to use + a USB serial console, then NSH needs to wait until the USB console is + connected and available. + * apps/examples/composite: Add a test of the USB composite device. + * apps/examples/telnetd: Move the tiny uIP shell example from + netutils/telnetd to examples/telnetd. Enhanced the telnetd daemon so that + it supports telnetd via a TTY device driver: A new TTY device driver is + created when each new telnet connection is created. The shell thread + is started with stdin, stdout, and stderror mapped to the TTY device. + * netutils/telnetd: The old uIP telnet demo is gone. In its place is a new + telnet infrastructure. The new telnet daemon creates sessions that are + "wrapped" as character devices and mapped to stdin, stdout, and stderr. + Now the telnet session can be inherited by spawned tasks. + * examples/telnetd: Add a test for the new telnet daemon. + * examples/telnetd/telnetd_driver.c: Move the internal socket structure from + the daemon's socket array into the driver's state data so that it will be + independent from the the telnetd daemon. + * apps/system/readline: Moved the old nuttx/lib/stdio/lib_fgets.c here + and renamed it as readline(). The old fgets was simplied and the overloaded + readline functionality was removed. + * apps/netutils/ftpd: Add an FTPD server (does not even compile on initial + checkin). + * apps/examples/ftpd: Add a test for the FTPD server (untest on initial + check-in).pascal-3.1 2012-xx-xx Gregory Nutt <gnutt@nuttx.org> buildroot-1.11 2012-xx-xx <gnutt@nuttx.org> diff --git a/configs/stm3210e-eval/src/up_adc.c b/configs/stm3210e-eval/src/up_adc.c index 6b1a8cb50e..c7c7e0c0a4 100644 --- a/configs/stm3210e-eval/src/up_adc.c +++ b/configs/stm3210e-eval/src/up_adc.c @@ -57,8 +57,7 @@ /************************************************************************************ * Definitions ************************************************************************************/ - -/* Configuration ************************************************************/ +/* Configuration ********************************************************************/ /* Up to 3 ADC interfaces are supported */ #if STM32_NADC < 3 diff --git a/drivers/Makefile b/drivers/Makefile index 9d804871e9..332233d521 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -70,6 +70,10 @@ ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y) CSRCS += ramdisk.c rwbuffer.c endif +ifeq ($(CONFIG_RAMLOG),y) + CSRCS += ramlog.c +endif + ifeq ($(CONFIG_CAN),y) CSRCS += can.c endif diff --git a/drivers/README.txt b/drivers/README.txt index e5a1483b22..0cddb93115 100644 --- a/drivers/README.txt +++ b/drivers/README.txt @@ -31,6 +31,19 @@ ramdisk.c a block driver that can be mounted as a files system. See include/nuttx/ramdisk.h. +ramlog.c + This is a driver that was intended to support debugging output, + aka syslogging, when the normal serial output is not available. + For example, if you are using a telnet or USB serial console, + the debug output will get lost. + + This driver is similar to a pipe in that it saves the debugging + output in a FIFO in RAM. It differs from a pipe in numerous + details as needed to support logging. + + This driver is built when CONFIG_RAMLOG is defined in the Nuttx + configuration. + rwbuffer.c A facility that can be use by any block driver in-order to add writing buffering and read-ahead buffering. diff --git a/drivers/ramlog.c b/drivers/ramlog.c new file mode 100644 index 0000000000..79f57636cd --- /dev/null +++ b/drivers/ramlog.c @@ -0,0 +1,590 @@ +/**************************************************************************** + * drivers/ramlog.c + * + * Copyright (C) 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 + +#include +#include +#include +#include +//#include + +#include + +#ifdef CONFIG_RAMLOG + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* Configuration ************************************************************/ +/* CONFIG_RAMLOG - Enables the RAM logging feature + * CONFIG_RAMLOG_CONSOLE - Use the RAM logging device as a system console. + * CONFIG_RAMLOG_SYSLOG - Use the RAM logging device for the syslogging + * interface. This should have: + * CONFIG_SYSLOG=ramlog + * CONFIG_RAMLOG_NPOLLWAITERS - The number of threads than can be waiting + * for this driver on poll(). Default: 4 + */ + +#ifndef CONFIG_RAMLOG_NPOLLWAITERS +# define CONFIG_RAMLOG_NPOLLWAITERS 4 +#endif + +#ifndef CONFIG_SYSLOG +# undef CONFIG_RAMLOG_SYSLOG +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct ramlog_dev_s +{ + volatile uint8_t rl_nwaiters; /* Number of threads waiting for data */ + volatile uint16_t rl_head; /* The head index (where data is added) */ + volatile uint16_t rl_tail; /* The tail index (where data is remove) */ + sem_t rl_exclsem; /* Enforces mutually exclusive access */ + sem_t rl_waitsem; /* Used to wait for data */ + size_t rl_bufsize; /* Size of the RAM buffer */ + FAR char *rl_buffer; /* Circular RAM buffer */ + + /* The following is a list if poll structures of threads waiting for + * driver events. The 'struct pollfd' reference for each open is also + * retained in the f_priv field of the 'struct file'. + */ + +#ifndef CONFIG_DISABLE_POLL + struct pollfd *rl_fds[CONFIG_RAMLOG_NPOLLWAITERS]; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static ssize_t ramlog_read(FAR struct file *, FAR char *, size_t); +static ssize_t ramlog_write(FAR struct file *, FAR const char *, size_t); +#ifndef CONFIG_DISABLE_POLL +static int ramlog_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_ramlogfops = +{ + 0, /* open */ + 0, /* close */ + ramlog_read, /* read */ + ramlog_write, /* write */ + 0, /* seek */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , ramlog_poll /* poll */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ramlog_pollnotify + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static void ramlog_pollnotify(FAR struct ramlog_dev_s *priv, pollevent_t eventset) +{ + FAR struct pollfd *fds; + irqstate_t flags; + int i; + + /* This function may be called from an interrupt handler */ + + for (i = 0; i < CONFIG_RAMLOG_NPOLLWAITERS; i++) + { + flags = irqsave(); + fds = priv->rl_fds[i]; + if (fds) + { + fds->revents |= (fds->events & eventset); + if (fds->revents != 0) + { + sem_post(fds->sem); + } + } + irqrestore(flags); + } +} +#else +# define ramlog_pollnotify(priv,event) +#endif + +/**************************************************************************** + * Name: ramlog_read + ****************************************************************************/ + +static ssize_t ramlog_read(FAR struct file *filep, FAR char *buffer, size_t len) +{ + struct inode *inode = filep->f_inode; + struct ramlog_dev_s *priv; + ssize_t nread; + char ch; + int ret; + + /* Some sanity checking */ + + DEBUGASSERT(inode && inode->i_private); + priv = inode->i_private; + + /* If the circular buffer is empty, then wait for something to be written + * to it. This function may NOT be called from an interrupt handler. + */ + + DEBUGASSERT(!up_interrupt_context()); + + /* Get exclusive access to the rl_tail index */ + + ret = sem_wait(&priv->rl_exclsem); + if (ret < 0) + { + return ret; + } + + /* Loop until something is read */ + + for (nread = 0; nread < len; ) + { + /* Get the next byte from the buffer */ + + if (priv->rl_head == priv->rl_tail) + { + /* The circular buffer is empty. Did we read anything? */ + + if (nread > 0) + { + /* Yes.. re-enable interrupts and the break out to return what + * we have. + */ + + break; + } + + /* If the driver was opened with O_NONBLOCK option, then don't wait. + * Re-enable interrupts and return EGAIN. + */ + + if (filep->f_oflags & O_NONBLOCK) + { + nread = -EAGAIN; + break; + } + + /* Otherwise, wait for something to be written to the circular + * buffer. Increment the number of waiters so that the ramlog_write() + * will not that it needs to post the semaphore to wake us up. + */ + + sched_lock(); + priv->rl_nwaiters++; + sem_post(&priv->rl_exclsem); + + /* We may now be pre-empted! But that should be okay because we + * have already incremented nwaiters. Pre-emptions is disabled + * but will be re-enabled while we are waiting. + */ + + ret = sem_wait(&priv->rl_waitsem); + + /* Interrupts will be disabled when we return. So the decrementing + * rl_nwaiters here is safe. + */ + + priv->rl_nwaiters--; + sched_unlock(); + + /* Did we successfully get the rl_waitsem? */ + + if (ret >= 0) + { + /* Yes... then retake the mutual exclusion semaphore */ + + ret = sem_wait(&priv->rl_exclsem); + } + + /* Was the semaphore wait successful? Did we successful re-take the + * mutual exclusion semaphore? + */ + + if (ret < 0) + { + /* No.. One of the two sem_wait's failed. */ + + int errval = errno; + + /* Were we awakened by a signal? Did we read anything before + * we received the signal? + */ + + if (errval != EINTR || nread >= 0) + { + /* Yes.. return the error. */ + + nread = -errval; + } + + /* Break out to return what we have. Note, we can't exactly + * "break" out because whichever error occurred, we do not hold + * the exclusion semaphore. + */ + + goto errout_without_sem; + } + } + else + { + /* The circular buffer is not empty, get the next byte from the + * tail index. + */ + + ch = priv->rl_buffer[priv->rl_tail]; + + /* Increment the tail index and re-enable interrupts */ + + if (++priv->rl_tail >= priv->rl_bufsize) + { + priv->rl_tail = 0; + } + + /* Add the character to the user buffer */ + + buffer[nread] = ch; + nread++; + } + } + + /* Relinquish the mutual exclusion semaphore */ + + sem_post(&priv->rl_exclsem); + + /* Notify all poll/select waiters that they can write to the FIFO */ + +errout_without_sem: + if (nread > 0) + { + ramlog_pollnotify(priv, POLLOUT); + } + return nread; +} + +/**************************************************************************** + * Name: ramlog_write + ****************************************************************************/ + +static ssize_t ramlog_write(FAR struct file *filep, FAR const char *buffer, size_t len) +{ + struct inode *inode = filep->f_inode; + struct ramlog_dev_s *priv; + irqstate_t flags; + ssize_t nwritten; + int nexthead; + int i; + + /* Some sanity checking */ + + DEBUGASSERT(inode && inode->i_private); + priv = inode->i_private; + + /* Loop until all of the bytes have been written. This function may be + * called from an interrupt handler! Semaphores cannot be used! + * + * The write logic only needs to modify the rl_head index. Therefore, + * there is a difference in the way that rl_head and rl_tail are protected: + * rl_tail is protected with a semaphore; rl_tail is protected by disabling + * interrupts. + */ + + for (nwritten = 0; nwritten < len; nwritten++) + { + /* Disable interrupts (in case we are NOT called from interrupt handler) */ + + flags = irqsave(); + + /* Calculate the write index AFTER the next byte is written */ + + nexthead = priv->rl_head + 1; + if (nexthead >= priv->rl_bufsize) + { + nexthead = 0; + } + + /* Would the next write overflow the circular buffer? */ + + if (nexthead == priv->rl_tail) + { + /* Yes... then break out of the loop to return the number of bytes + * written. The data to be written is dropped on the floor. + */ + + return nwritten; + } + + /* No... copy the byte and re-enable interrupts */ + + priv->rl_buffer[priv->rl_head] = buffer[nwritten]; + priv->rl_head = nexthead; + irqrestore(flags); + } + + /* Was anything written? */ + + if (nwritten > 0) + { + /* Are there threads waiting for read data? */ + + flags = irqsave(); + for (i = 0; i < priv->rl_nwaiters; i++) + { + /* Yes.. Notify all of the waiting readers that more data is available */ + + sem_post(&priv->rl_waitsem); + } + + /* Notify all poll/select waiters that they can write to the FIFO */ + + ramlog_pollnotify(priv, POLLIN); + } + + /* Return the number of bytes written */ + + return nwritten; +} + +/**************************************************************************** + * Name: ramlog_poll + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +int ramlog_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct ramlog_dev_s *priv; + pollevent_t eventset; + int ndx; + int ret; + int i; + + /* Some sanity checking */ + + DEBUGASSERT(inode && inode->i_private); + priv = inode->i_private; + + /* Get exclusive access to the poll structures */ + + ret = sem_wait(&priv->rl_exclsem); + if (ret < 0) + { + int errval = errno; + return -errval; + } + + /* Are we setting up the poll? Or tearing it down? */ + + if (setup) + { + /* This is a request to set up the poll. Find an available + * slot for the poll structure reference + */ + + for (i = 0; i < CONFIG_RAMLOG_NPOLLWAITERS; i++) + { + /* Find an available slot */ + + if (!priv->rl_fds[i]) + { + /* Bind the poll structure and this slot */ + + priv->rl_fds[i] = fds; + fds->priv = &priv->rl_fds[i]; + break; + } + } + + if (i >= CONFIG_RAMLOG_NPOLLWAITERS) + { + fds->priv = NULL; + ret = -EBUSY; + goto errout; + } + + /* Should immediately notify on any of the requested events? + * First, check if the xmit buffer is full. + */ + + eventset = 0; + + ndx = priv->rl_head + 1; + if (ndx >= priv->rl_bufsize) + { + ndx = 0; + } + + if (ndx != priv->rl_tail) + { + eventset |= POLLOUT; + } + + /* Check if the receive buffer is empty */ + + if (priv->rl_head != priv->rl_tail) + { + eventset |= POLLIN; + } + + if (eventset) + { + ramlog_pollnotify(priv, eventset); + } + + } + else if (fds->priv) + { + /* This is a request to tear down the poll. */ + + struct pollfd **slot = (struct pollfd **)fds->priv; + +#ifdef CONFIG_DEBUG + if (!slot) + { + ret = -EIO; + goto errout; + } +#endif + + /* Remove all memory of the poll setup */ + + *slot = NULL; + fds->priv = NULL; + } + +errout: + sem_post(&priv->rl_exclsem); + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ramlog_register + * + * Description: + * Create the RAM logging device and register it at the specified path. + * Mostly likely this path will be /dev/console + * + ****************************************************************************/ + +int ramlog_register(FAR const char *devpath, FAR char *buffer, size_t buflen) +{ + FAR struct ramlog_dev_s *priv; + int ret = -ENOMEM; + + /* Sanity checking */ + + DEBUGASSERT(devpath && buffer && buflen > 1); + + /* Allocate a RAM logging device structure */ + + priv = (struct ramlog_dev_s *)kzalloc(sizeof(struct ramlog_dev_s)); + if (priv) + { + /* Initialize the non-zero values in the RAM logging device structure */ + + sem_init(&priv->rl_exclsem, 0, 1); + sem_init(&priv->rl_waitsem, 0, 0); + priv->rl_bufsize = buflen; + priv->rl_buffer = buffer; + + /* Register the character driver */ + + ret = register_driver(devpath, &g_ramlogfops, 0666, priv); + if (ret < 0) + { + kfree(priv); + } + } + + return ret; +} + +/**************************************************************************** + * Name: ramlog + * + * Description: + * This is the low-level system logging interface. The debugging/syslogging + * interfaces are lib_rawprintf() and lib_lowprinf(). The difference is + * the lib_rawprintf() writes to fd=1 (stdout) and lib_lowprintf() uses + * a lower level interface that works from interrupt handlers. This + * function is a a low-level interface used to implement lib_lowprintf() + * when CONFIG_RAMLOG_SYSLOG=y and CONFIG_SYSLOG=ramlog + * + ****************************************************************************/ + +#ifdef CONFIG_RAMLOG_SYSLOG +# warning "Missing logic" +#endif + +#endif /* CONFIG_RAMLOG */