summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-02-11 00:32:53 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-02-11 00:32:53 +0000
commit24af177eb1a3e7036f8a3ee5342970ddeb151124 (patch)
treecb21dffb332218477b6ad468053c61df6b9d8830
parentd52c77f6349fdb61f27818e2f85a217509f949ce (diff)
downloadnuttx-24af177eb1a3e7036f8a3ee5342970ddeb151124.tar.gz
nuttx-24af177eb1a3e7036f8a3ee5342970ddeb151124.tar.bz2
nuttx-24af177eb1a3e7036f8a3ee5342970ddeb151124.zip
Add a RAM-based logging device
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4379 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog3
-rw-r--r--nuttx/Documentation/NuttX.html127
-rw-r--r--nuttx/configs/stm3210e-eval/src/up_adc.c3
-rw-r--r--nuttx/drivers/Makefile4
-rw-r--r--nuttx/drivers/README.txt13
-rw-r--r--nuttx/drivers/ramlog.c590
6 files changed, 734 insertions, 6 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index a5856e50f..1de3de5f0 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/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/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index 51ac872aa..c604b9dad 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
- <p>Last Updated: February 4, 2012</p>
+ <p>Last Updated: February 9, 2012</p>
</td>
</tr>
</table>
@@ -707,7 +707,6 @@
<li>Touchscreen, USB keyboard, GPIO-based buttons and keypads. </li>
</p>
</tr>
-</table></center>
<tr>
<td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td>
@@ -719,7 +718,21 @@
<td><br></td>
<td>
<p>
- <li>Support for Analog-to-Digital converters.</li>
+ <li>Support for Analog-to-Digital conversion (ADC) and Digital-to-Analog conversion (DAC).</li>
+ </p>
+</tr>
+
+<tr>
+ <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td>
+ <td bgcolor="#5eaee1">
+ <b>Motor Control</b>
+ </td>
+</tr>
+<tr>
+ <td><br></td>
+ <td>
+ <p>
+ <li>Pulse width modulation (PWM) / Pulse count modulation.</li>
</p>
</tr>
</table></center>
@@ -2838,9 +2851,115 @@ buildroot-1.10 2011-05-06 &lt;gnutt@nuttx.org&gt;
<ul><pre>
nuttx-6.15 2012-xx-xx Gregory Nutt &lt;gnutt@nuttx.org&gt;
+ * 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 &quot;advanced&quot; 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 &quot;fuel guage&quot;
+ * 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 &quot;phony&quot; 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 &lt;gnutt@nuttx.org&gt;
-pascal-3.1 2012-xx-xx Gregory Nutt &lt;gnutt@nuttx.org&gt;
+ * 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
+ &quot;wrapped&quot; 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 &lt;gnutt@nuttx.org&gt;
buildroot-1.11 2012-xx-xx &lt;gnutt@nuttx.org&gt;
diff --git a/nuttx/configs/stm3210e-eval/src/up_adc.c b/nuttx/configs/stm3210e-eval/src/up_adc.c
index 6b1a8cb50..c7c7e0c0a 100644
--- a/nuttx/configs/stm3210e-eval/src/up_adc.c
+++ b/nuttx/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/nuttx/drivers/Makefile b/nuttx/drivers/Makefile
index 9d804871e..332233d52 100644
--- a/nuttx/drivers/Makefile
+++ b/nuttx/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/nuttx/drivers/README.txt b/nuttx/drivers/README.txt
index e5a1483b2..0cddb9311 100644
--- a/nuttx/drivers/README.txt
+++ b/nuttx/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/nuttx/drivers/ramlog.c b/nuttx/drivers/ramlog.c
new file mode 100644
index 000000000..79f57636c
--- /dev/null
+++ b/nuttx/drivers/ramlog.c
@@ -0,0 +1,590 @@
+/****************************************************************************
+ * drivers/ramlog.c
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <poll.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/fs.h>
+#include <nuttx/arch.h>
+//#include <nuttx/ramlog.h>
+
+#include <arch/irq.h>
+
+#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 */