diff --git a/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig b/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig index 291d19f901..e72982560b 100644 --- a/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig +++ b/boards/arm/stm32f7/stm32f746-ws/configs/nsh/defconfig @@ -32,6 +32,7 @@ CONFIG_CDCACM=y CONFIG_CDCACM_EPINTIN_HSSIZE=512 CONFIG_DEBUG_SYMBOLS=y CONFIG_DRIVER_NOTE=y +CONFIG_DRIVER_NOTERAM_BUFSIZE=512 CONFIG_FAT_DMAMEMORY=y CONFIG_FAT_LCNAMES=y CONFIG_FAT_LFN=y @@ -71,7 +72,6 @@ CONFIG_SCHED_HPWORKSTACKSIZE=1800 CONFIG_SCHED_INSTRUMENTATION=y CONFIG_SCHED_LPWORK=y CONFIG_SCHED_LPWORKSTACKSIZE=1800 -CONFIG_SCHED_NOTE_BUFSIZE=512 CONFIG_SCHED_WAITPID=y CONFIG_SDCLONE_DISABLE=y CONFIG_SIG_SIGWORK=4 diff --git a/drivers/note/Kconfig b/drivers/note/Kconfig index 32060812f1..2286d635af 100644 --- a/drivers/note/Kconfig +++ b/drivers/note/Kconfig @@ -3,11 +3,19 @@ # see the file kconfig-language.txt in the NuttX tools repository. # -menu "Note Driver Support" - -config DRIVER_NOTE - bool "Scheduler instrumentation driver" +menuconfig DRIVER_NOTE + bool "Note Driver Support" + depends on SCHED_INSTRUMENTATION default n + +if DRIVER_NOTE + +choice + prompt "Note driver selection" + default DRIVER_NOTERAM + +config DRIVER_NOTERAM + bool "Note RAM driver" depends on !SCHED_INSTRUMENTATION_CSECTION && (!SCHED_INSTRUMENTATION_SPINLOCK || !SMP) ---help--- If this option is selected, then in-memory buffering logic is @@ -33,12 +41,18 @@ config DRIVER_NOTE sched_note_get() causes several additional entries to be added from the note buffer in order to remove one entry. -config SCHED_NOTE_BUFSIZE - int "Instrumentation buffer size" - depends on DRIVER_NOTE +config DRIVER_NOTEARCH + bool "Note Arch driver" + ---help--- + The note driver is provided by arch specific code. + +endchoice + +config DRIVER_NOTERAM_BUFSIZE + int "Note RAM buffer size" + depends on DRIVER_NOTERAM default 2048 ---help--- - The size of the in-memory, circular instrumentation buffer (in - bytes). + The size of the in-memory, circular instrumentation buffer (in bytes). -endmenu +endif diff --git a/drivers/note/Make.defs b/drivers/note/Make.defs index 91c0dc358d..d978711af7 100644 --- a/drivers/note/Make.defs +++ b/drivers/note/Make.defs @@ -22,5 +22,9 @@ ifeq ($(CONFIG_DRIVER_NOTE),y) CSRCS += note_driver.c endif +ifeq ($(CONFIG_DRIVER_NOTERAM),y) + CSRCS += noteram_driver.c +endif + DEPPATH += --dep-path note VPATH += :note diff --git a/drivers/note/note_driver.c b/drivers/note/note_driver.c index 6d917567cb..fe104efafe 100644 --- a/drivers/note/note_driver.c +++ b/drivers/note/note_driver.c @@ -1,35 +1,20 @@ /**************************************************************************** * drivers/note/note_driver.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -37,440 +22,39 @@ * Included Files ****************************************************************************/ -#include - -#include -#include -#include -#include - -#include -#include -#include - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct note_info_s -{ - volatile unsigned int ni_head; - volatile unsigned int ni_tail; - uint8_t ni_buffer[CONFIG_SCHED_NOTE_BUFSIZE]; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static ssize_t note_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct file_operations note_fops = -{ - NULL, /* open */ - NULL, /* close */ - note_read, /* read */ - NULL, /* write */ - NULL, /* seek */ - NULL, /* ioctl */ - NULL /* poll */ -#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS - , 0 /* unlink */ -#endif -}; - -static struct note_info_s g_note_info; - -#ifdef CONFIG_SMP -static volatile spinlock_t g_note_lock; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: note_next - * - * Description: - * Return the circular buffer index at offset from the specified index - * value, handling wraparound - * - * Input Parameters: - * ndx - Old circular buffer index - * - * Returned Value: - * New circular buffer index - * - ****************************************************************************/ - -static inline unsigned int note_next(unsigned int ndx, unsigned int offset) -{ - ndx += offset; - if (ndx >= CONFIG_SCHED_NOTE_BUFSIZE) - { - ndx -= CONFIG_SCHED_NOTE_BUFSIZE; - } - - return ndx; -} - -/**************************************************************************** - * Name: note_length - * - * Description: - * Length of data currently in circular buffer. - * - * Input Parameters: - * None - * - * Returned Value: - * Length of data currently in circular buffer. - * - ****************************************************************************/ - -static unsigned int note_length(void) -{ - unsigned int head = g_note_info.ni_head; - unsigned int tail = g_note_info.ni_tail; - - if (tail > head) - { - head += CONFIG_SCHED_NOTE_BUFSIZE; - } - - return head - tail; -} - -/**************************************************************************** - * Name: note_remove - * - * Description: - * Remove the variable length note from the tail of the circular buffer - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - * Assumptions: - * We are within a critical section. - * - ****************************************************************************/ - -static void note_remove(void) -{ - FAR struct note_common_s *note; - unsigned int tail; - unsigned int length; - - /* Get the tail index of the circular buffer */ - - tail = g_note_info.ni_tail; - DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE); - - /* Get the length of the note at the tail index */ - - note = (FAR struct note_common_s *)&g_note_info.ni_buffer[tail]; - length = note->nc_length; - DEBUGASSERT(length <= note_length()); - - /* Increment the tail index to remove the entire note from the circular - * buffer. - */ - - g_note_info.ni_tail = note_next(tail, length); -} - -/**************************************************************************** - * Name: sched_note_get - * - * Description: - * Remove the next note from the tail of the circular buffer. The note - * is also removed from the circular buffer to make room for further notes. - * - * Input Parameters: - * buffer - Location to return the next note - * buflen - The length of the user provided buffer. - * - * Returned Value: - * On success, the positive, non-zero length of the return note is - * provided. Zero is returned only if the circular buffer is empty. A - * negated errno value is returned in the event of any failure. - * - ****************************************************************************/ - -static ssize_t sched_note_get(FAR uint8_t *buffer, size_t buflen) -{ - FAR struct note_common_s *note; - irqstate_t flags; - unsigned int remaining; - unsigned int tail; - ssize_t notelen; - size_t circlen; - - DEBUGASSERT(buffer != NULL); - flags = enter_critical_section(); - - /* Verify that the circular buffer is not empty */ - - circlen = note_length(); - if (circlen <= 0) - { - notelen = 0; - goto errout_with_csection; - } - - /* Get the index to the tail of the circular buffer */ - - tail = g_note_info.ni_tail; - DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE); - - /* Get the length of the note at the tail index */ - - note = (FAR struct note_common_s *)&g_note_info.ni_buffer[tail]; - notelen = note->nc_length; - DEBUGASSERT(notelen <= circlen); - - /* Is the user buffer large enough to hold the note? */ - - if (buflen < notelen) - { - /* Remove the large note so that we do not get constipated. */ - - note_remove(); - - /* and return an error */ - - notelen = -EFBIG; - goto errout_with_csection; - } - - /* Loop until the note has been transferred to the user buffer */ - - remaining = (unsigned int)notelen; - while (remaining > 0) - { - /* Copy the next byte at the tail index */ - - *buffer++ = g_note_info.ni_buffer[tail]; - - /* Adjust indices and counts */ - - tail = note_next(tail, 1); - remaining--; - } - - g_note_info.ni_tail = tail; - -errout_with_csection: - leave_critical_section(flags); - return notelen; -} - -/**************************************************************************** - * Name: sched_note_size - * - * Description: - * Return the size of the next note at the tail of the circular buffer. - * - * Input Parameters: - * None. - * - * Returned Value: - * Zero is returned if the circular buffer is empty. Otherwise, the size - * of the next note is returned. - * - ****************************************************************************/ - -static ssize_t sched_note_size(void) -{ - FAR struct note_common_s *note; - irqstate_t flags; - unsigned int tail; - ssize_t notelen; - size_t circlen; - - flags = enter_critical_section(); - - /* Verify that the circular buffer is not empty */ - - circlen = note_length(); - if (circlen <= 0) - { - notelen = 0; - goto errout_with_csection; - } - - /* Get the index to the tail of the circular buffer */ - - tail = g_note_info.ni_tail; - DEBUGASSERT(tail < CONFIG_SCHED_NOTE_BUFSIZE); - - /* Get the length of the note at the tail index */ - - note = (FAR struct note_common_s *)&g_note_info.ni_buffer[tail]; - notelen = note->nc_length; - DEBUGASSERT(notelen <= circlen); - -errout_with_csection: - leave_critical_section(flags); - return notelen; -} - -/**************************************************************************** - * Name: note_read - ****************************************************************************/ - -static ssize_t note_read(FAR struct file *filep, FAR char *buffer, - size_t buflen) -{ - ssize_t notelen; - ssize_t retlen ; - - DEBUGASSERT(filep != 0 && buffer != NULL && buflen > 0); - - /* Then loop, adding as many notes as possible to the user buffer. */ - - retlen = 0; - sched_lock(); - do - { - /* Get the next note (removing it from the buffer) */ - - notelen = sched_note_get((FAR uint8_t *)buffer, buflen); - if (notelen < 0) - { - /* We were unable to read the next note, probably because it will - * not fit into the user buffer. - */ - - if (retlen == 0) - { - /* If nothing was read then report the error. Otherwise, - * just silently drop the note. - */ - - retlen = notelen; - } - - break; - } - - /* Update pointers from the note that was transferred */ - - retlen += notelen; - buffer += notelen; - buflen -= notelen; - - /* Will the next note fit? There is a race here and even if the next - * note will fit, it may fail still when sched_note_get() is called. - * - * It won't fit (or an error occurred). Return what we have without - * trying to get the next note (which would cause it to be deleted). - */ - - notelen = sched_note_size(); - } - while (notelen > 0 && notelen <= buflen); - - sched_unlock(); - return retlen; -} +#include +#include /**************************************************************************** * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: sched_note_add - * - * Description: - * Add the variable length note to the transport layer - * - * Input Parameters: - * note - The note buffer - * notelen - The buffer length - * - * Returned Value: - * None - * - * Assumptions: - * We are within a critical section. - * - ****************************************************************************/ - -void sched_note_add(FAR const void *note, size_t notelen) -{ - FAR const char *buf = note; - unsigned int head; - unsigned int next; - -#ifdef CONFIG_SMP - irqstate_t flags = up_irq_save(); - spin_lock_wo_note(&g_note_lock); -#endif - - /* Get the index to the head of the circular buffer */ - - DEBUGASSERT(note != NULL && notelen < CONFIG_SCHED_NOTE_BUFSIZE); - head = g_note_info.ni_head; - - /* Loop until all bytes have been transferred to the circular buffer */ - - while (notelen > 0) - { - /* Get the next head index. Would it collide with the current tail - * index? - */ - - next = note_next(head, 1); - if (next == g_note_info.ni_tail) - { - /* Yes, then remove the note at the tail index */ - - note_remove(); - } - - /* Save the next byte at the head index */ - - g_note_info.ni_buffer[head] = *buf++; - - head = next; - notelen--; - } - - g_note_info.ni_head = head; - -#ifdef CONFIG_SMP - spin_unlock_wo_note(&g_note_lock); - up_irq_restore(flags); -#endif -} - /**************************************************************************** * Name: note_register * * Description: - * Register a serial driver at /dev/note that can be used by an - * application to read data from the circular note buffer. + * Register sched note related drivers at /dev folder that can be used by + * an application to read or filter the note data. * * Input Parameters: * None. * * Returned Value: - * Zero is returned if the circular buffer is empty. Otherwise, a negated - * errno value is returned. + * Zero on succress. A negated errno value is returned on a failure. * ****************************************************************************/ int note_register(void) { - return register_driver("/dev/note", ¬e_fops, 0666, NULL); + int ret = 0; + +#ifdef CONFIG_DRIVER_NOTERAM + ret = noteram_register(); + if (ret < 0) + { + return ret; + } +#endif + + return ret; } diff --git a/drivers/note/noteram_driver.c b/drivers/note/noteram_driver.c new file mode 100644 index 0000000000..6ca2d22717 --- /dev/null +++ b/drivers/note/noteram_driver.c @@ -0,0 +1,477 @@ +/**************************************************************************** + * drivers/note/noteram_driver.c + * + * Copyright (C) 2016 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 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct noteram_info_s +{ + volatile unsigned int ni_head; + volatile unsigned int ni_tail; + uint8_t ni_buffer[CONFIG_DRIVER_NOTERAM_BUFSIZE]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static ssize_t noteram_read(FAR struct file *filep, + FAR char *buffer, size_t buflen); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_noteram_fops = +{ + NULL, /* open */ + NULL, /* close */ + noteram_read, /* read */ + NULL, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL /* poll */ +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , 0 /* unlink */ +#endif +}; + +static struct noteram_info_s g_noteram_info; + +#ifdef CONFIG_SMP +static volatile spinlock_t g_noteram_lock; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: noteram_next + * + * Description: + * Return the circular buffer index at offset from the specified index + * value, handling wraparound + * + * Input Parameters: + * ndx - Old circular buffer index + * + * Returned Value: + * New circular buffer index + * + ****************************************************************************/ + +static inline unsigned int noteram_next(unsigned int ndx, + unsigned int offset) +{ + ndx += offset; + if (ndx >= CONFIG_DRIVER_NOTERAM_BUFSIZE) + { + ndx -= CONFIG_DRIVER_NOTERAM_BUFSIZE; + } + + return ndx; +} + +/**************************************************************************** + * Name: noteram_length + * + * Description: + * Length of data currently in circular buffer. + * + * Input Parameters: + * None + * + * Returned Value: + * Length of data currently in circular buffer. + * + ****************************************************************************/ + +static unsigned int noteram_length(void) +{ + unsigned int head = g_noteram_info.ni_head; + unsigned int tail = g_noteram_info.ni_tail; + + if (tail > head) + { + head += CONFIG_DRIVER_NOTERAM_BUFSIZE; + } + + return head - tail; +} + +/**************************************************************************** + * Name: noteram_remove + * + * Description: + * Remove the variable length note from the tail of the circular buffer + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * We are within a critical section. + * + ****************************************************************************/ + +static void noteram_remove(void) +{ + FAR struct note_common_s *note; + unsigned int tail; + unsigned int length; + + /* Get the tail index of the circular buffer */ + + tail = g_noteram_info.ni_tail; + DEBUGASSERT(tail < CONFIG_DRIVER_NOTERAM_BUFSIZE); + + /* Get the length of the note at the tail index */ + + note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[tail]; + length = note->nc_length; + DEBUGASSERT(length <= noteram_length()); + + /* Increment the tail index to remove the entire note from the circular + * buffer. + */ + + g_noteram_info.ni_tail = noteram_next(tail, length); +} + +/**************************************************************************** + * Name: noteram_get + * + * Description: + * Remove the next note from the tail of the circular buffer. The note + * is also removed from the circular buffer to make room for further notes. + * + * Input Parameters: + * buffer - Location to return the next note + * buflen - The length of the user provided buffer. + * + * Returned Value: + * On success, the positive, non-zero length of the return note is + * provided. Zero is returned only if the circular buffer is empty. A + * negated errno value is returned in the event of any failure. + * + ****************************************************************************/ + +static ssize_t noteram_get(FAR uint8_t *buffer, size_t buflen) +{ + FAR struct note_common_s *note; + irqstate_t flags; + unsigned int remaining; + unsigned int tail; + ssize_t notelen; + size_t circlen; + + DEBUGASSERT(buffer != NULL); + flags = enter_critical_section(); + + /* Verify that the circular buffer is not empty */ + + circlen = noteram_length(); + if (circlen <= 0) + { + notelen = 0; + goto errout_with_csection; + } + + /* Get the index to the tail of the circular buffer */ + + tail = g_noteram_info.ni_tail; + DEBUGASSERT(tail < CONFIG_DRIVER_NOTERAM_BUFSIZE); + + /* Get the length of the note at the tail index */ + + note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[tail]; + notelen = note->nc_length; + DEBUGASSERT(notelen <= circlen); + + /* Is the user buffer large enough to hold the note? */ + + if (buflen < notelen) + { + /* Remove the large note so that we do not get constipated. */ + + noteram_remove(); + + /* and return an error */ + + notelen = -EFBIG; + goto errout_with_csection; + } + + /* Loop until the note has been transferred to the user buffer */ + + remaining = (unsigned int)notelen; + while (remaining > 0) + { + /* Copy the next byte at the tail index */ + + *buffer++ = g_noteram_info.ni_buffer[tail]; + + /* Adjust indices and counts */ + + tail = noteram_next(tail, 1); + remaining--; + } + + g_noteram_info.ni_tail = tail; + +errout_with_csection: + leave_critical_section(flags); + return notelen; +} + +/**************************************************************************** + * Name: noteram_size + * + * Description: + * Return the size of the next note at the tail of the circular buffer. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero is returned if the circular buffer is empty. Otherwise, the size + * of the next note is returned. + * + ****************************************************************************/ + +static ssize_t noteram_size(void) +{ + FAR struct note_common_s *note; + irqstate_t flags; + unsigned int tail; + ssize_t notelen; + size_t circlen; + + flags = enter_critical_section(); + + /* Verify that the circular buffer is not empty */ + + circlen = noteram_length(); + if (circlen <= 0) + { + notelen = 0; + goto errout_with_csection; + } + + /* Get the index to the tail of the circular buffer */ + + tail = g_noteram_info.ni_tail; + DEBUGASSERT(tail < CONFIG_DRIVER_NOTERAM_BUFSIZE); + + /* Get the length of the note at the tail index */ + + note = (FAR struct note_common_s *)&g_noteram_info.ni_buffer[tail]; + notelen = note->nc_length; + DEBUGASSERT(notelen <= circlen); + +errout_with_csection: + leave_critical_section(flags); + return notelen; +} + +/**************************************************************************** + * Name: noteram_read + ****************************************************************************/ + +static ssize_t noteram_read(FAR struct file *filep, + FAR char *buffer, size_t buflen) +{ + ssize_t notelen; + ssize_t retlen ; + + DEBUGASSERT(filep != 0 && buffer != NULL && buflen > 0); + + /* Then loop, adding as many notes as possible to the user buffer. */ + + retlen = 0; + sched_lock(); + do + { + /* Get the next note (removing it from the buffer) */ + + notelen = noteram_get((FAR uint8_t *)buffer, buflen); + if (notelen < 0) + { + /* We were unable to read the next note, probably because it will + * not fit into the user buffer. + */ + + if (retlen == 0) + { + /* If nothing was read then report the error. Otherwise, + * just silently drop the note. + */ + + retlen = notelen; + } + + break; + } + + /* Update pointers from the note that was transferred */ + + retlen += notelen; + buffer += notelen; + buflen -= notelen; + + /* Will the next note fit? There is a race here and even if the next + * note will fit, it may fail still when noteram_get() is called. + * + * It won't fit (or an error occurred). Return what we have without + * trying to get the next note (which would cause it to be deleted). + */ + + notelen = noteram_size(); + } + while (notelen > 0 && notelen <= buflen); + + sched_unlock(); + return retlen; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sched_note_add + * + * Description: + * Add the variable length note to the transport layer + * + * Input Parameters: + * note - The note buffer + * notelen - The buffer length + * + * Returned Value: + * None + * + * Assumptions: + * We are within a critical section. + * + ****************************************************************************/ + +void sched_note_add(FAR const void *note, size_t notelen) +{ + FAR const char *buf = note; + unsigned int head; + unsigned int next; + +#ifdef CONFIG_SMP + irqstate_t flags = up_irq_save(); + spin_lock_wo_note(&g_noteram_lock); +#endif + + /* Get the index to the head of the circular buffer */ + + DEBUGASSERT(note != NULL && notelen < CONFIG_DRIVER_NOTERAM_BUFSIZE); + head = g_noteram_info.ni_head; + + /* Loop until all bytes have been transferred to the circular buffer */ + + while (notelen > 0) + { + /* Get the next head index. Would it collide with the current tail + * index? + */ + + next = noteram_next(head, 1); + if (next == g_noteram_info.ni_tail) + { + /* Yes, then remove the note at the tail index */ + + noteram_remove(); + } + + /* Save the next byte at the head index */ + + g_noteram_info.ni_buffer[head] = *buf++; + + head = next; + notelen--; + } + + g_noteram_info.ni_head = head; + +#ifdef CONFIG_SMP + spin_unlock_wo_note(&g_noteram_lock); + up_irq_restore(flags); +#endif +} + +/**************************************************************************** + * Name: noteram_register + * + * Description: + * Register a serial driver at /dev/note that can be used by an + * application to read data from the circular note buffer. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero on succress. A negated errno value is returned on a failure. + * + ****************************************************************************/ + +int noteram_register(void) +{ + return register_driver("/dev/note", &g_noteram_fops, 0666, NULL); +} diff --git a/include/nuttx/note/note_driver.h b/include/nuttx/note/note_driver.h index 62df063715..8f417f6929 100644 --- a/include/nuttx/note/note_driver.h +++ b/include/nuttx/note/note_driver.h @@ -27,8 +27,6 @@ #include -#ifdef CONFIG_SCHED_INSTRUMENTATION - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -47,8 +45,8 @@ * Name: note_register * * Description: - * Register a serial driver at /dev/note that can be used by an - * application to read data from the circular note buffer. + * Register sched note related drivers at /dev folder that can be used by + * an application to read or filter the note data. * * Input Parameters: * None. @@ -64,6 +62,4 @@ int note_register(void); #endif /* defined(__KERNEL__) || defined(CONFIG_BUILD_FLAT) */ -#endif /* CONFIG_SCHED_INSTRUMENTATION */ - #endif /* __INCLUDE_NUTTX_NOTE_NOTE_DRIVER_H */ diff --git a/include/nuttx/note/noteram_driver.h b/include/nuttx/note/noteram_driver.h new file mode 100644 index 0000000000..73709122a9 --- /dev/null +++ b/include/nuttx/note/noteram_driver.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * include/nuttx/note/noteram_driver.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NOTE_NOTERAM_DRIVER_H +#define __INCLUDE_NUTTX_NOTE_NOTERAM_DRIVER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#if defined(__KERNEL__) || defined(CONFIG_BUILD_FLAT) + +/**************************************************************************** + * Name: noteram_register + * + * Description: + * Register RAM note driver at /dev/note that can be used by an + * application to read note data from the circular note buffer. + * + * Input Parameters: + * None. + * + * Returned Value: + * Zero on succress. A negated errno value is returned on a failure. + * + ****************************************************************************/ + +#ifdef CONFIG_DRIVER_NOTERAM +int noteram_register(void); +#endif + +#endif /* defined(__KERNEL__) || defined(CONFIG_BUILD_FLAT) */ + +#endif /* __INCLUDE_NUTTX_NOTE_NOTERAM_DRIVER_H */