changeset 3932:e4afd3faf339

printk: added a ring buffer backend with shell commands
author Alexandre Becoulet <alexandre.becoulet@free.fr>
date Fri, 18 May 2018 13:35:30 +0200
parents 8a96ed703460
children 511e79e2ba7f
files mutek/Makefile mutek/mutek.config mutek/printk_ring.c
diffstat 3 files changed, 173 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mutek/Makefile	Fri May 18 13:32:31 2018 +0200
+++ b/mutek/Makefile	Fri May 18 13:35:30 2018 +0200
@@ -12,6 +12,7 @@
 objs-$(CONFIG_MUTEK_MEMALLOC_SIMPLE) += memory_allocator_simple.o
 objs-$(CONFIG_COMPILE_INSTRUMENT) += instrument.o
 objs-$(CONFIG_MUTEK_PRINTK) += printk.o
+objs-$(CONFIG_MUTEK_PRINTK_RING) += printk_ring.o
 objs-$(CONFIG_MUTEK_LOGO) += mutek_logo_320x200.o
 objs-$(CONFIG_VMEM_PHYS_ALLOC) += page_alloc.o
 
--- a/mutek/mutek.config	Fri May 18 13:32:31 2018 +0200
+++ b/mutek/mutek.config	Fri May 18 13:35:30 2018 +0200
@@ -286,6 +286,26 @@
   default 1
 %config end
 
+%config CONFIG_MUTEK_PRINTK_RING
+  desc Store printk output in a ring buffer
+  parent CONFIG_MUTEK_PRINTK
+  depend CONFIG_MUTEK_SHELL
+  require CONFIG_MUTEK_PRINTK_RING_SIZE>0
+%config end
+
+%config CONFIG_MUTEK_PRINTK_RING_SIZE
+  desc Specifies the size of the ring buffer used store the printk output
+  parent CONFIG_MUTEK_PRINTK_RING
+  flags value
+  default 512
+%config end
+
+%init INIT_MUTEK_PRINTK_RING
+  parent CONFIG_MUTEK_PRINTK_RING
+  during INIT_MUTEK_PRINTK
+  function printk_ring_init
+%init end
+
 ######################################################################
 #		Vmem
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mutek/printk_ring.c	Fri May 18 13:35:30 2018 +0200
@@ -0,0 +1,152 @@
+/*
+    This file is part of MutekH.
+
+    MutekH is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as
+    published by the Free Software Foundation; version 2.1 of the
+    License.
+
+    MutekH is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with MutekH; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+    02110-1301 USA.
+
+    Copyright Alexandre Becoulet <alexandre.becoulet@free.fr> (c) 2018
+*/
+
+#include <mutek/printk.h>
+#include <mutek/startup.h>
+#include <mutek/shell.h>
+#include <termui/term.h>
+
+#include <stdlib.h>
+
+static char printk_ring[CONFIG_MUTEK_PRINTK_RING_SIZE];
+static uint32_t printk_ring_size;
+static uint32_t printk_ring_ptr;
+
+static PRINTK_HANDLER(printk_ring_out)
+{
+  /* skip head of string if longer than buffer */
+  if (len > CONFIG_MUTEK_PRINTK_RING_SIZE)
+    {
+      str += len - CONFIG_MUTEK_PRINTK_RING_SIZE;
+      len = CONFIG_MUTEK_PRINTK_RING_SIZE;
+    }
+
+  uint32_t end = (printk_ring_ptr + printk_ring_size)
+                 % CONFIG_MUTEK_PRINTK_RING_SIZE;
+
+  if (len + printk_ring_size >= CONFIG_MUTEK_PRINTK_RING_SIZE)
+    {
+      /* drop buffer head */
+      printk_ring_ptr = (printk_ring_ptr + len + printk_ring_size) % CONFIG_MUTEK_PRINTK_RING_SIZE;
+      printk_ring_size = CONFIG_MUTEK_PRINTK_RING_SIZE;
+    }
+  else
+    {
+      printk_ring_size += len;
+    }
+
+  /* write tail of string at ring[0] if overflow */
+  uint32_t l = CONFIG_MUTEK_PRINTK_RING_SIZE - end;
+  if (len > l)
+    {
+      memcpy(printk_ring, str + l, len - l);
+      len = l;
+    }
+
+  /* write head of string */
+  memcpy(printk_ring + end, str, len);
+}
+
+static TERMUI_CON_COMMAND_PROTOTYPE(shell_logk_tail)
+{
+  uint_fast16_t lines = argc ? atoi(argv[0]) : 5;
+
+  if (printk_ring_size == 0)
+    return 0;
+
+  uint32_t end = printk_ring_ptr + printk_ring_size;
+  uint32_t lptr = end, ptr = end;
+
+  /* look backward for end of line */
+  while (lines > 0)
+    {
+      if (ptr == printk_ring_ptr)
+        {
+          lptr = ptr;
+          break;
+        }
+
+      if (printk_ring[(ptr + CONFIG_MUTEK_PRINTK_RING_SIZE - 1)
+                      % CONFIG_MUTEK_PRINTK_RING_SIZE] == '\n')
+        {
+          lptr = ptr;
+          lines--;
+        }
+
+      ptr--;
+    }
+
+  /* display buffer tail */
+  ptr = lptr % CONFIG_MUTEK_PRINTK_RING_SIZE;
+
+  if (end % CONFIG_MUTEK_PRINTK_RING_SIZE <= ptr)
+    {
+      termui_con_putsl(con, printk_ring + lptr % CONFIG_MUTEK_PRINTK_RING_SIZE,
+                       CONFIG_MUTEK_PRINTK_RING_SIZE - ptr);
+      termui_con_putsl(con, printk_ring, end % CONFIG_MUTEK_PRINTK_RING_SIZE);
+    }
+  else
+    {
+      termui_con_putsl(con, printk_ring + ptr, end - lptr);
+    }
+
+  return 0;
+}
+
+static TERMUI_CON_COMMAND_PROTOTYPE(shell_logk_write)
+{
+  writek(argv[0], argl[0]);
+  return 0;
+}
+
+static TERMUI_CON_COMMAND_PROTOTYPE(shell_logk_clear)
+{
+  printk_ring_size = 0;
+  printk_ring_ptr = 0;
+  return 0;
+}
+
+static TERMUI_CON_GROUP_DECL(shell_logk_subgroup) =
+{
+  TERMUI_CON_ENTRY(shell_logk_tail, "tail",
+    TERMUI_CON_ARGS(0, 1)
+  )
+
+  TERMUI_CON_ENTRY(shell_logk_write, "write",
+    TERMUI_CON_ARGS(1, 1)
+  )
+
+  TERMUI_CON_ENTRY(shell_logk_clear, "clear",
+  )
+
+  TERMUI_CON_LIST_END
+};
+
+MUTEK_SHELL_ROOT_GROUP(shell_logk_subgroup, "logk");
+
+void printk_ring_init()
+{
+  printk_ring_size = 0;
+  printk_ring_ptr = 0;
+
+  static struct printk_backend_s printk_ring_backend;
+  printk_register(&printk_ring_backend, printk_ring_out);
+}