From 27e1398be3821f814aee4eaf7627b2d8fb5c4934 Mon Sep 17 00:00:00 2001
From: Giovanni Di Sirio <gdisirio@gmail.com>
Date: Sat, 20 Feb 2016 13:51:02 +0000
Subject: Shell reorganization.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8913 35acf78f-673a-0410-8e92-d51de3d6d3f4
---
 os/common/oslib/include/chdynamic.h      |   2 +
 os/common/oslib/src/chdynamic.c          |  35 ++++
 os/hal/lib/streams/streams.mk            |   6 +
 os/various/cpp_wrappers/chcpp.mk         |   6 +-
 os/various/fatfs_bindings/fatfs.mk       |  10 +-
 os/various/lwip_bindings/lwip.mk         |  72 ++++----
 os/various/shell.c                       | 274 -------------------------------
 os/various/shell.h                       |  82 ---------
 os/various/shell/shell.c                 | 248 ++++++++++++++++++++++++++++
 os/various/shell/shell.h                 | 110 +++++++++++++
 os/various/shell/shell.mk                |   5 +
 os/various/shell/shell_cmd.c             | 193 ++++++++++++++++++++++
 os/various/shell/shell_cmd.h             | 106 ++++++++++++
 testhal/STM32/STM32F7xx/USB_CDC/Makefile |   9 +-
 testhal/STM32/STM32F7xx/USB_CDC/main.c   |  59 +------
 15 files changed, 755 insertions(+), 462 deletions(-)
 create mode 100644 os/hal/lib/streams/streams.mk
 delete mode 100644 os/various/shell.c
 delete mode 100644 os/various/shell.h
 create mode 100644 os/various/shell/shell.c
 create mode 100644 os/various/shell/shell.h
 create mode 100644 os/various/shell/shell.mk
 create mode 100644 os/various/shell/shell_cmd.c
 create mode 100644 os/various/shell/shell_cmd.h

diff --git a/os/common/oslib/include/chdynamic.h b/os/common/oslib/include/chdynamic.h
index fa00bd83e..35b47cd93 100644
--- a/os/common/oslib/include/chdynamic.h
+++ b/os/common/oslib/include/chdynamic.h
@@ -74,10 +74,12 @@ extern "C" {
 #if CH_CFG_USE_HEAP == TRUE
   thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
                                 tprio_t prio, tfunc_t pf, void *arg);
+  void chThdFreeToHeap(thread_t *tp);
 #endif
 #if CH_CFG_USE_MEMPOOLS == TRUE
   thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
                                       tfunc_t pf, void *arg);
+  void chThdFreeToMemoryPool(thread_t *tp, memory_pool_t *mp);
 #endif
 #ifdef __cplusplus
 }
diff --git a/os/common/oslib/src/chdynamic.c b/os/common/oslib/src/chdynamic.c
index 7d8b609be..80555a928 100644
--- a/os/common/oslib/src/chdynamic.c
+++ b/os/common/oslib/src/chdynamic.c
@@ -96,6 +96,23 @@ thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
 
   return chThdCreateStatic(wsp, size, prio, pf, arg);
 }
+
+/**
+ * @brief   Releases a thread working area into the owner heap.
+ * @pre     The thread must have been created using @p chThdCreateFromHeap().
+ * @pre     The thread must be in the state @p CH_STATE_FINAL (terminated).
+ *
+ * @param[in] tp        the pointer to the thread
+ *
+ * @api
+ */
+void chThdFreeToHeap(thread_t *tp) {
+
+  chDbgCheck(tp != NULL);
+  chDbgAssert(tp->state == CH_STATE_FINAL, "not terminated");
+
+  chHeapFree(chthdGetStackLimitX(tp));
+}
 #endif /* CH_CFG_USE_HEAP == TRUE */
 
 #if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
@@ -143,6 +160,24 @@ thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
 
   return chThdCreateStatic(wsp, mp->object_size, prio, pf, arg);
 }
+
+/**
+ * @brief   Releases a thread working area into a memory pool.
+ * @pre     The thread must have been created using @p chThdCreateFromMemoryPool().
+ * @pre     The thread must be in the state @p CH_STATE_FINAL (terminated).
+ *
+ * @param[in] tp        the pointer to the thread
+ * @param[in] mp        pointer to a @p memory_pool_t structure
+ *
+ * @api
+ */
+void chThdFreeToMemoryPool(thread_t *tp, memory_pool_t *mp) {
+
+  chDbgCheck((tp != NULL) && (mp != NULL));
+  chDbgAssert(tp->state == CH_STATE_FINAL, "not terminated");
+
+  chPoolFree(mp, (void *)chthdGetStackLimitX(tp));
+}
 #endif /* CH_CFG_USE_MEMPOOLS == TRUE */
 
 #endif /* CH_CFG_USE_DYNAMIC == TRUE */
diff --git a/os/hal/lib/streams/streams.mk b/os/hal/lib/streams/streams.mk
new file mode 100644
index 000000000..fee61e1fe
--- /dev/null
+++ b/os/hal/lib/streams/streams.mk
@@ -0,0 +1,6 @@
+# RT Shell files.
+STREAMSSRC = $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
+             $(CHIBIOS)/os/hal/lib/streams/memstreams.c \
+             $(CHIBIOS)/os/hal/lib/streams/nullstreams.c
+
+STREAMSINC = $(CHIBIOS)/os/hal/lib/streams
diff --git a/os/various/cpp_wrappers/chcpp.mk b/os/various/cpp_wrappers/chcpp.mk
index 9eb4885bc..64f931586 100644
--- a/os/various/cpp_wrappers/chcpp.mk
+++ b/os/various/cpp_wrappers/chcpp.mk
@@ -1,5 +1,5 @@
 # C++ wrapper files.
-CHCPPSRC = ${CHIBIOS}/os/various/cpp_wrappers/ch.cpp \
-           ${CHIBIOS}/os/various/cpp_wrappers/syscalls_cpp.cpp
+CHCPPSRC = $(CHIBIOS)/os/various/cpp_wrappers/ch.cpp \
+           $(CHIBIOS)/os/various/cpp_wrappers/syscalls_cpp.cpp
 
-CHCPPINC = ${CHIBIOS}/os/various/cpp_wrappers
+CHCPPINC = $(CHIBIOS)/os/various/cpp_wrappers
diff --git a/os/various/fatfs_bindings/fatfs.mk b/os/various/fatfs_bindings/fatfs.mk
index d395db860..b5441d026 100644
--- a/os/various/fatfs_bindings/fatfs.mk
+++ b/os/various/fatfs_bindings/fatfs.mk
@@ -1,7 +1,7 @@
 # FATFS files.
-FATFSSRC = ${CHIBIOS}/os/various/fatfs_bindings/fatfs_diskio.c \
-           ${CHIBIOS}/os/various/fatfs_bindings/fatfs_syscall.c \
-           ${CHIBIOS}/ext/fatfs/src/ff.c \
-           ${CHIBIOS}/ext/fatfs/src/option/unicode.c
+FATFSSRC = $(CHIBIOS)/os/various/fatfs_bindings/fatfs_diskio.c \
+           $(CHIBIOS)/os/various/fatfs_bindings/fatfs_syscall.c \
+           $(CHIBIOS)/ext/fatfs/src/ff.c \
+           $(CHIBIOS)/ext/fatfs/src/option/unicode.c
 
-FATFSINC = ${CHIBIOS}/ext/fatfs/src
+FATFSINC = $(CHIBIOS)/ext/fatfs/src
diff --git a/os/various/lwip_bindings/lwip.mk b/os/various/lwip_bindings/lwip.mk
index afaaf1454..2ab332a09 100644
--- a/os/various/lwip_bindings/lwip.mk
+++ b/os/various/lwip_bindings/lwip.mk
@@ -1,54 +1,54 @@
 # List of the required lwIP files.
-LWIP = 	${CHIBIOS}/ext/lwip
+LWIP = 	$(CHIBIOS)/ext/lwip
 
 LWBINDSRC = \
         $(CHIBIOS)/os/various/lwip_bindings/lwipthread.c \
         $(CHIBIOS)/os/various/lwip_bindings/arch/sys_arch.c
 
 LWNETIFSRC = \
-        ${LWIP}/src/netif/etharp.c
+        $(LWIP)/src/netif/etharp.c
 
 LWCORESRC = \
-        ${LWIP}/src/core/dhcp.c \
-        ${LWIP}/src/core/dns.c \
-        ${LWIP}/src/core/init.c \
-        ${LWIP}/src/core/mem.c \
-        ${LWIP}/src/core/memp.c \
-        ${LWIP}/src/core/netif.c \
-        ${LWIP}/src/core/pbuf.c \
-        ${LWIP}/src/core/raw.c \
-        ${LWIP}/src/core/stats.c \
-        ${LWIP}/src/core/sys.c \
-        ${LWIP}/src/core/tcp.c \
-        ${LWIP}/src/core/tcp_in.c \
-        ${LWIP}/src/core/tcp_out.c \
-        ${LWIP}/src/core/udp.c
+        $(LWIP)/src/core/dhcp.c \
+        $(LWIP)/src/core/dns.c \
+        $(LWIP)/src/core/init.c \
+        $(LWIP)/src/core/mem.c \
+        $(LWIP)/src/core/memp.c \
+        $(LWIP)/src/core/netif.c \
+        $(LWIP)/src/core/pbuf.c \
+        $(LWIP)/src/core/raw.c \
+        $(LWIP)/src/core/stats.c \
+        $(LWIP)/src/core/sys.c \
+        $(LWIP)/src/core/tcp.c \
+        $(LWIP)/src/core/tcp_in.c \
+        $(LWIP)/src/core/tcp_out.c \
+        $(LWIP)/src/core/udp.c
 
 LWIPV4SRC = \
-        ${LWIP}/src/core/ipv4/autoip.c \
-        ${LWIP}/src/core/ipv4/icmp.c \
-        ${LWIP}/src/core/ipv4/igmp.c \
-        ${LWIP}/src/core/ipv4/inet.c \
-        ${LWIP}/src/core/ipv4/inet_chksum.c \
-        ${LWIP}/src/core/ipv4/ip.c \
-        ${LWIP}/src/core/ipv4/ip_addr.c \
-        ${LWIP}/src/core/ipv4/ip_frag.c \
-        ${LWIP}/src/core/def.c \
-        ${LWIP}/src/core/timers.c
+        $(LWIP)/src/core/ipv4/autoip.c \
+        $(LWIP)/src/core/ipv4/icmp.c \
+        $(LWIP)/src/core/ipv4/igmp.c \
+        $(LWIP)/src/core/ipv4/inet.c \
+        $(LWIP)/src/core/ipv4/inet_chksum.c \
+        $(LWIP)/src/core/ipv4/ip.c \
+        $(LWIP)/src/core/ipv4/ip_addr.c \
+        $(LWIP)/src/core/ipv4/ip_frag.c \
+        $(LWIP)/src/core/def.c \
+        $(LWIP)/src/core/timers.c
 
 LWAPISRC = \
-        ${LWIP}/src/api/api_lib.c \
-        ${LWIP}/src/api/api_msg.c \
-        ${LWIP}/src/api/err.c \
-        ${LWIP}/src/api/netbuf.c \
-        ${LWIP}/src/api/netdb.c \
-        ${LWIP}/src/api/netifapi.c \
-        ${LWIP}/src/api/sockets.c \
-        ${LWIP}/src/api/tcpip.c
+        $(LWIP)/src/api/api_lib.c \
+        $(LWIP)/src/api/api_msg.c \
+        $(LWIP)/src/api/err.c \
+        $(LWIP)/src/api/netbuf.c \
+        $(LWIP)/src/api/netdb.c \
+        $(LWIP)/src/api/netifapi.c \
+        $(LWIP)/src/api/sockets.c \
+        $(LWIP)/src/api/tcpip.c
 
 LWSRC = $(LWBINDSRC) $(LWNETIFSRC) $(LWCORESRC) $(LWIPV4SRC) $(LWAPISRC)
 
 LWINC = \
         $(CHIBIOS)/os/various/lwip_bindings \
-        ${LWIP}/src/include \
-        ${LWIP}/src/include/ipv4
+        $(LWIP)/src/include \
+        $(LWIP)/src/include/ipv4
diff --git a/os/various/shell.c b/os/various/shell.c
deleted file mode 100644
index a60f9b479..000000000
--- a/os/various/shell.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
-    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
-
-    Licensed 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.
-*/
-
-/**
- * @file    shell.c
- * @brief   Simple CLI shell code.
- *
- * @addtogroup SHELL
- * @{
- */
-
-#include <string.h>
-
-#include "ch.h"
-#include "hal.h"
-#include "shell.h"
-#include "chprintf.h"
-
-/**
- * @brief   Shell termination event source.
- */
-event_source_t shell_terminated;
-
-static char *_strtok(char *str, const char *delim, char **saveptr) {
-  char *token;
-  if (str)
-    *saveptr = str;
-  token = *saveptr;
-
-  if (!token)
-    return NULL;
-
-  token += strspn(token, delim);
-  *saveptr = strpbrk(token, delim);
-  if (*saveptr)
-    *(*saveptr)++ = '\0';
-
-  return *token ? token : NULL;
-}
-
-static void usage(BaseSequentialStream *chp, char *p) {
-
-  chprintf(chp, "Usage: %s\r\n", p);
-}
-
-static void list_commands(BaseSequentialStream *chp, const ShellCommand *scp) {
-
-  while (scp->sc_name != NULL) {
-    chprintf(chp, "%s ", scp->sc_name);
-    scp++;
-  }
-}
-
-static void cmd_info(BaseSequentialStream *chp, int argc, char *argv[]) {
-
-  (void)argv;
-  if (argc > 0) {
-    usage(chp, "info");
-    return;
-  }
-
-  chprintf(chp, "Kernel:       %s\r\n", CH_KERNEL_VERSION);
-#ifdef PORT_COMPILER_NAME
-  chprintf(chp, "Compiler:     %s\r\n", PORT_COMPILER_NAME);
-#endif
-  chprintf(chp, "Architecture: %s\r\n", PORT_ARCHITECTURE_NAME);
-#ifdef PORT_CORE_VARIANT_NAME
-  chprintf(chp, "Core Variant: %s\r\n", PORT_CORE_VARIANT_NAME);
-#endif
-#ifdef PORT_INFO
-  chprintf(chp, "Port Info:    %s\r\n", PORT_INFO);
-#endif
-#ifdef PLATFORM_NAME
-  chprintf(chp, "Platform:     %s\r\n", PLATFORM_NAME);
-#endif
-#ifdef BOARD_NAME
-  chprintf(chp, "Board:        %s\r\n", BOARD_NAME);
-#endif
-#ifdef __DATE__
-#ifdef __TIME__
-  chprintf(chp, "Build time:   %s%s%s\r\n", __DATE__, " - ", __TIME__);
-#endif
-#endif
-}
-
-static void cmd_systime(BaseSequentialStream *chp, int argc, char *argv[]) {
-
-  (void)argv;
-  if (argc > 0) {
-    usage(chp, "systime");
-    return;
-  }
-  chprintf(chp, "%lu\r\n", (unsigned long)chVTGetSystemTime());
-}
-
-/**
- * @brief   Array of the default commands.
- */
-static ShellCommand local_commands[] = {
-  {"info", cmd_info},
-  {"systime", cmd_systime},
-  {NULL, NULL}
-};
-
-static bool cmdexec(const ShellCommand *scp, BaseSequentialStream *chp,
-                      char *name, int argc, char *argv[]) {
-
-  while (scp->sc_name != NULL) {
-    if (strcmp(scp->sc_name, name) == 0) {
-      scp->sc_function(chp, argc, argv);
-      return false;
-    }
-    scp++;
-  }
-  return true;
-}
-
-/**
- * @brief   Shell thread function.
- *
- * @param[in] p         pointer to a @p BaseSequentialStream object
- */
-THD_FUNCTION(shellThread, p) {
-  int n;
-  BaseSequentialStream *chp = ((ShellConfig *)p)->sc_channel;
-  const ShellCommand *scp = ((ShellConfig *)p)->sc_commands;
-  char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH];
-  char *args[SHELL_MAX_ARGUMENTS + 1];
-
-  chRegSetThreadName("shell");
-  chprintf(chp, "\r\nChibiOS/RT Shell\r\n");
-  while (true) {
-    chprintf(chp, "ch> ");
-    if (shellGetLine(chp, line, sizeof(line))) {
-      chprintf(chp, "\r\nlogout");
-      break;
-    }
-    lp = _strtok(line, " \t", &tokp);
-    cmd = lp;
-    n = 0;
-    while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) {
-      if (n >= SHELL_MAX_ARGUMENTS) {
-        chprintf(chp, "too many arguments\r\n");
-        cmd = NULL;
-        break;
-      }
-      args[n++] = lp;
-    }
-    args[n] = NULL;
-    if (cmd != NULL) {
-      if (strcmp(cmd, "exit") == 0) {
-        if (n > 0) {
-          usage(chp, "exit");
-          continue;
-        }
-        break;
-      }
-      else if (strcmp(cmd, "help") == 0) {
-        if (n > 0) {
-          usage(chp, "help");
-          continue;
-        }
-        chprintf(chp, "Commands: help exit ");
-        list_commands(chp, local_commands);
-        if (scp != NULL)
-          list_commands(chp, scp);
-        chprintf(chp, "\r\n");
-      }
-      else if (cmdexec(local_commands, chp, cmd, n, args) &&
-          ((scp == NULL) || cmdexec(scp, chp, cmd, n, args))) {
-        chprintf(chp, "%s", cmd);
-        chprintf(chp, " ?\r\n");
-      }
-    }
-  }
-  shellExit(MSG_OK);
-}
-
-/**
- * @brief   Shell manager initialization.
- *
- * @api
- */
-void shellInit(void) {
-
-  chEvtObjectInit(&shell_terminated);
-}
-
-/**
- * @brief   Terminates the shell.
- * @note    Must be invoked from the command handlers.
- * @note    Does not return.
- *
- * @param[in] msg       shell exit code
- *
- * @api
- */
-void shellExit(msg_t msg) {
-
-  /* Atomically broadcasting the event source and terminating the thread,
-     there is not a chSysUnlock() because the thread terminates upon return.*/
-  chSysLock();
-  chEvtBroadcastI(&shell_terminated);
-  chThdExitS(msg);
-}
-
-/**
- * @brief   Reads a whole line from the input channel.
- * @note    Input chars are echoed on the same stream object with the
- *          following exceptions:
- *          - DEL and BS are echoed as BS-SPACE-BS.
- *          - CR is echoed as CR-LF.
- *          - 0x4 is echoed as "^D".
- *          - Other values below 0x20 are not echoed.
- *          .
- *
- * @param[in] chp       pointer to a @p BaseSequentialStream object
- * @param[in] line      pointer to the line buffer
- * @param[in] size      buffer maximum length
- * @return              The operation status.
- * @retval true         the channel was reset or CTRL-D pressed.
- * @retval false        operation successful.
- *
- * @api
- */
-bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size) {
-  char *p = line;
-
-  while (true) {
-    char c;
-
-    if (chSequentialStreamRead(chp, (uint8_t *)&c, 1) == 0)
-      return true;
-    if (c == 4) {
-      chprintf(chp, "^D");
-      return true;
-    }
-    if ((c == 8) || (c == 127)) {
-      if (p != line) {
-        chSequentialStreamPut(chp, c);
-        chSequentialStreamPut(chp, 0x20);
-        chSequentialStreamPut(chp, c);
-        p--;
-      }
-      continue;
-    }
-    if (c == '\r') {
-      chprintf(chp, "\r\n");
-      *p = 0;
-      return false;
-    }
-    if (c < 0x20)
-      continue;
-    if (p < line + size - 1) {
-      chSequentialStreamPut(chp, c);
-      *p++ = (char)c;
-    }
-  }
-}
-
-/** @} */
diff --git a/os/various/shell.h b/os/various/shell.h
deleted file mode 100644
index 9ee73d4dc..000000000
--- a/os/various/shell.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
-
-    Licensed 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.
-*/
-
-/**
- * @file    shell.h
- * @brief   Simple CLI shell header.
- *
- * @addtogroup SHELL
- * @{
- */
-
-#ifndef _SHELL_H_
-#define _SHELL_H_
-
-/**
- * @brief   Shell maximum input line length.
- */
-#if !defined(SHELL_MAX_LINE_LENGTH) || defined(__DOXYGEN__)
-#define SHELL_MAX_LINE_LENGTH       64
-#endif
-
-/**
- * @brief   Shell maximum arguments per command.
- */
-#if !defined(SHELL_MAX_ARGUMENTS) || defined(__DOXYGEN__)
-#define SHELL_MAX_ARGUMENTS         4
-#endif
-
-/**
- * @brief   Command handler function type.
- */
-typedef void (*shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[]);
-
-/**
- * @brief   Custom command entry type.
- */
-typedef struct {
-  const char            *sc_name;           /**< @brief Command name.       */
-  shellcmd_t            sc_function;        /**< @brief Command function.   */
-} ShellCommand;
-
-/**
- * @brief   Shell descriptor type.
- */
-typedef struct {
-  BaseSequentialStream  *sc_channel;        /**< @brief I/O channel associated
-                                                 to the shell.              */
-  const ShellCommand    *sc_commands;       /**< @brief Shell extra commands
-                                                 table.                     */
-} ShellConfig;
-
-#if !defined(__DOXYGEN__)
-extern event_source_t shell_terminated;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void shellInit(void);
-  THD_FUNCTION(shellThread, p);
-  void shellExit(msg_t msg);
-  bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SHELL_H_ */
-
-/** @} */
diff --git a/os/various/shell/shell.c b/os/various/shell/shell.c
new file mode 100644
index 000000000..379b6ddf0
--- /dev/null
+++ b/os/various/shell/shell.c
@@ -0,0 +1,248 @@
+/*
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+    Licensed 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.
+*/
+
+/**
+ * @file    shell.c
+ * @brief   Simple CLI shell code.
+ *
+ * @addtogroup SHELL
+ * @{
+ */
+
+#include <string.h>
+
+#include "ch.h"
+#include "hal.h"
+#include "shell.h"
+#include "shell_cmd.h"
+#include "chprintf.h"
+
+/*===========================================================================*/
+/* Module local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module exported variables.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Shell termination event source.
+ */
+event_source_t shell_terminated;
+
+/*===========================================================================*/
+/* Module local types.                                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local variables.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local functions.                                                   */
+/*===========================================================================*/
+
+static char *_strtok(char *str, const char *delim, char **saveptr) {
+  char *token;
+  if (str)
+    *saveptr = str;
+  token = *saveptr;
+
+  if (!token)
+    return NULL;
+
+  token += strspn(token, delim);
+  *saveptr = strpbrk(token, delim);
+  if (*saveptr)
+    *(*saveptr)++ = '\0';
+
+  return *token ? token : NULL;
+}
+
+static void usage(BaseSequentialStream *chp, char *p) {
+
+  chprintf(chp, "Usage: %s\r\n", p);
+}
+
+static void list_commands(BaseSequentialStream *chp, const ShellCommand *scp) {
+
+  while (scp->sc_name != NULL) {
+    chprintf(chp, "%s ", scp->sc_name);
+    scp++;
+  }
+}
+
+static bool cmdexec(const ShellCommand *scp, BaseSequentialStream *chp,
+                      char *name, int argc, char *argv[]) {
+
+  while (scp->sc_name != NULL) {
+    if (strcmp(scp->sc_name, name) == 0) {
+      scp->sc_function(chp, argc, argv);
+      return false;
+    }
+    scp++;
+  }
+  return true;
+}
+
+/*===========================================================================*/
+/* Module exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Shell thread function.
+ *
+ * @param[in] p         pointer to a @p BaseSequentialStream object
+ */
+THD_FUNCTION(shellThread, p) {
+  int n;
+  BaseSequentialStream *chp = ((ShellConfig *)p)->sc_channel;
+  const ShellCommand *scp = ((ShellConfig *)p)->sc_commands;
+  char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH];
+  char *args[SHELL_MAX_ARGUMENTS + 1];
+
+  chRegSetThreadName("shell");
+  chprintf(chp, "\r\nChibiOS/RT Shell\r\n");
+  while (true) {
+    chprintf(chp, "ch> ");
+    if (shellGetLine(chp, line, sizeof(line))) {
+      chprintf(chp, "\r\nlogout");
+      break;
+    }
+    lp = _strtok(line, " \t", &tokp);
+    cmd = lp;
+    n = 0;
+    while ((lp = _strtok(NULL, " \t", &tokp)) != NULL) {
+      if (n >= SHELL_MAX_ARGUMENTS) {
+        chprintf(chp, "too many arguments\r\n");
+        cmd = NULL;
+        break;
+      }
+      args[n++] = lp;
+    }
+    args[n] = NULL;
+    if (cmd != NULL) {
+      if (strcmp(cmd, "exit") == 0) {
+        if (n > 0) {
+          usage(chp, "exit");
+          continue;
+        }
+        break;
+      }
+      else if (strcmp(cmd, "help") == 0) {
+        if (n > 0) {
+          usage(chp, "help");
+          continue;
+        }
+        chprintf(chp, "Commands: help exit ");
+        list_commands(chp, shell_local_commands);
+        if (scp != NULL)
+          list_commands(chp, scp);
+        chprintf(chp, "\r\n");
+      }
+      else if (cmdexec(shell_local_commands, chp, cmd, n, args) &&
+          ((scp == NULL) || cmdexec(scp, chp, cmd, n, args))) {
+        chprintf(chp, "%s", cmd);
+        chprintf(chp, " ?\r\n");
+      }
+    }
+  }
+  shellExit(MSG_OK);
+}
+
+/**
+ * @brief   Shell manager initialization.
+ *
+ * @api
+ */
+void shellInit(void) {
+
+  chEvtObjectInit(&shell_terminated);
+}
+
+/**
+ * @brief   Terminates the shell.
+ * @note    Must be invoked from the command handlers.
+ * @note    Does not return.
+ *
+ * @param[in] msg       shell exit code
+ *
+ * @api
+ */
+void shellExit(msg_t msg) {
+
+  /* Atomically broadcasting the event source and terminating the thread,
+     there is not a chSysUnlock() because the thread terminates upon return.*/
+  chSysLock();
+  chEvtBroadcastI(&shell_terminated);
+  chThdExitS(msg);
+}
+
+/**
+ * @brief   Reads a whole line from the input channel.
+ * @note    Input chars are echoed on the same stream object with the
+ *          following exceptions:
+ *          - DEL and BS are echoed as BS-SPACE-BS.
+ *          - CR is echoed as CR-LF.
+ *          - 0x4 is echoed as "^D".
+ *          - Other values below 0x20 are not echoed.
+ *          .
+ *
+ * @param[in] chp       pointer to a @p BaseSequentialStream object
+ * @param[in] line      pointer to the line buffer
+ * @param[in] size      buffer maximum length
+ * @return              The operation status.
+ * @retval true         the channel was reset or CTRL-D pressed.
+ * @retval false        operation successful.
+ *
+ * @api
+ */
+bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size) {
+  char *p = line;
+
+  while (true) {
+    char c;
+
+    if (chSequentialStreamRead(chp, (uint8_t *)&c, 1) == 0)
+      return true;
+    if (c == 4) {
+      chprintf(chp, "^D");
+      return true;
+    }
+    if ((c == 8) || (c == 127)) {
+      if (p != line) {
+        chSequentialStreamPut(chp, c);
+        chSequentialStreamPut(chp, 0x20);
+        chSequentialStreamPut(chp, c);
+        p--;
+      }
+      continue;
+    }
+    if (c == '\r') {
+      chprintf(chp, "\r\n");
+      *p = 0;
+      return false;
+    }
+    if (c < 0x20)
+      continue;
+    if (p < line + size - 1) {
+      chSequentialStreamPut(chp, c);
+      *p++ = (char)c;
+    }
+  }
+}
+
+/** @} */
diff --git a/os/various/shell/shell.h b/os/various/shell/shell.h
new file mode 100644
index 000000000..f6607cb43
--- /dev/null
+++ b/os/various/shell/shell.h
@@ -0,0 +1,110 @@
+/*
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+    Licensed 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.
+*/
+
+/**
+ * @file    shell.h
+ * @brief   Simple CLI shell header.
+ *
+ * @addtogroup SHELL
+ * @{
+ */
+
+#ifndef _SHELL_H_
+#define _SHELL_H_
+
+/*===========================================================================*/
+/* Module constants.                                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Shell maximum input line length.
+ */
+#if !defined(SHELL_MAX_LINE_LENGTH) || defined(__DOXYGEN__)
+#define SHELL_MAX_LINE_LENGTH       64
+#endif
+
+/**
+ * @brief   Shell maximum arguments per command.
+ */
+#if !defined(SHELL_MAX_ARGUMENTS) || defined(__DOXYGEN__)
+#define SHELL_MAX_ARGUMENTS         4
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module data structures and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Command handler function type.
+ */
+typedef void (*shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[]);
+
+/**
+ * @brief   Custom command entry type.
+ */
+typedef struct {
+  const char            *sc_name;           /**< @brief Command name.       */
+  shellcmd_t            sc_function;        /**< @brief Command function.   */
+} ShellCommand;
+
+/**
+ * @brief   Shell descriptor type.
+ */
+typedef struct {
+  BaseSequentialStream  *sc_channel;        /**< @brief I/O channel associated
+                                                 to the shell.              */
+  const ShellCommand    *sc_commands;       /**< @brief Shell extra commands
+                                                 table.                     */
+} ShellConfig;
+
+/*===========================================================================*/
+/* Module macros.                                                            */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern event_source_t shell_terminated;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void shellInit(void);
+  THD_FUNCTION(shellThread, p);
+  void shellExit(msg_t msg);
+  bool shellGetLine(BaseSequentialStream *chp, char *line, unsigned size);
+#ifdef __cplusplus
+}
+#endif
+
+/*===========================================================================*/
+/* Module inline functions.                                                  */
+/*===========================================================================*/
+
+#endif /* _SHELL_H_ */
+
+/** @} */
diff --git a/os/various/shell/shell.mk b/os/various/shell/shell.mk
new file mode 100644
index 000000000..de735d516
--- /dev/null
+++ b/os/various/shell/shell.mk
@@ -0,0 +1,5 @@
+# RT Shell files.
+SHELLSRC = $(CHIBIOS)/os/various/shell/shell.c \
+           $(CHIBIOS)/os/various/shell/shell_cmd.c
+
+SHELLINC = $(CHIBIOS)/os/various/shell
diff --git a/os/various/shell/shell_cmd.c b/os/various/shell/shell_cmd.c
new file mode 100644
index 000000000..1a8bba4a4
--- /dev/null
+++ b/os/various/shell/shell_cmd.c
@@ -0,0 +1,193 @@
+/*
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+    Licensed 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.
+*/
+
+/**
+ * @file    shell_cmd.c
+ * @brief   Simple CLI shell common commands code.
+ *
+ * @addtogroup SHELL
+ * @{
+ */
+
+#include <string.h>
+
+#include "ch.h"
+#include "hal.h"
+#include "shell.h"
+#include "shell_cmd.h"
+#include "chprintf.h"
+
+#if (SHELL_CMD_TEST_ENABLED == TRUE) || defined(__DOXYGEN__)
+#include "test.h"
+#endif
+
+/*===========================================================================*/
+/* Module local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local types.                                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local variables.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local functions.                                                   */
+/*===========================================================================*/
+
+static void usage(BaseSequentialStream *chp, char *p) {
+
+  chprintf(chp, "Usage: %s\r\n", p);
+}
+
+#if (SHELL_CMD_INFO_ENABLED == TRUE) || defined(__DOXYGEN__)
+static void cmd_info(BaseSequentialStream *chp, int argc, char *argv[]) {
+
+  (void)argv;
+  if (argc > 0) {
+    usage(chp, "info");
+    return;
+  }
+
+  chprintf(chp, "Kernel:       %s\r\n", CH_KERNEL_VERSION);
+#ifdef PORT_COMPILER_NAME
+  chprintf(chp, "Compiler:     %s\r\n", PORT_COMPILER_NAME);
+#endif
+  chprintf(chp, "Architecture: %s\r\n", PORT_ARCHITECTURE_NAME);
+#ifdef PORT_CORE_VARIANT_NAME
+  chprintf(chp, "Core Variant: %s\r\n", PORT_CORE_VARIANT_NAME);
+#endif
+#ifdef PORT_INFO
+  chprintf(chp, "Port Info:    %s\r\n", PORT_INFO);
+#endif
+#ifdef PLATFORM_NAME
+  chprintf(chp, "Platform:     %s\r\n", PLATFORM_NAME);
+#endif
+#ifdef BOARD_NAME
+  chprintf(chp, "Board:        %s\r\n", BOARD_NAME);
+#endif
+#ifdef __DATE__
+#ifdef __TIME__
+  chprintf(chp, "Build time:   %s%s%s\r\n", __DATE__, " - ", __TIME__);
+#endif
+#endif
+}
+#endif
+
+#if (SHELL_CMD_SYSTIME_ENABLED == TRUE) || defined(__DOXYGEN__)
+static void cmd_systime(BaseSequentialStream *chp, int argc, char *argv[]) {
+
+  (void)argv;
+  if (argc > 0) {
+    usage(chp, "systime");
+    return;
+  }
+  chprintf(chp, "%lu\r\n", (unsigned long)chVTGetSystemTime());
+}
+#endif
+
+#if (SHELL_CMD_MEM_ENABLED == TRUE) || defined(__DOXYGEN__)
+static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
+  size_t n, total, largest;
+
+  (void)argv;
+  if (argc > 0) {
+    chprintf(chp, "Usage: mem\r\n");
+    return;
+  }
+  n = chHeapStatus(NULL, &total, &largest);
+  chprintf(chp, "core free memory : %u bytes\r\n", chCoreGetStatusX());
+  chprintf(chp, "heap fragments   : %u\r\n", n);
+  chprintf(chp, "heap free total  : %u bytes\r\n", total);
+  chprintf(chp, "heap free largest: %u bytes\r\n", largest);
+}
+#endif
+
+#if (SHELL_CMD_THREADS_ENABLED == TRUE) || defined(__DOXYGEN__)
+static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
+  static const char *states[] = {CH_STATE_NAMES};
+  thread_t *tp;
+
+  (void)argv;
+  if (argc > 0) {
+    chprintf(chp, "Usage: threads\r\n");
+    return;
+  }
+  chprintf(chp, "stklimit    stack     addr prio     state         name\r\n");
+  tp = chRegFirstThread();
+  do {
+    chprintf(chp, "%08lx %08lx %08lx %4lu %9s %12s\r\n",
+             (uint32_t)tp->stklimit, (uint32_t)tp->ctx.r13, (uint32_t)tp,
+             (uint32_t)tp->prio, states[tp->state],
+             tp->name == NULL ? "" : tp->name);
+    tp = chRegNextThread(tp);
+  } while (tp != NULL);
+}
+#endif
+
+#if (SHELL_CMD_TEST_ENABLED == TRUE) || defined(__DOXYGEN__)
+static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
+  thread_t *tp;
+
+  (void)argv;
+  if (argc > 0) {
+    chprintf(chp, "Usage: test\r\n");
+    return;
+  }
+  tp = chThdCreateFromHeap(NULL, SHELL_CMD_TEST_WA_SIZE, chThdGetPriorityX(),
+                           TestThread, chp);
+  if (tp == NULL) {
+    chprintf(chp, "out of memory\r\n");
+    return;
+  }
+  chThdWait(tp);
+  chThdFreeToHeap(tp);
+}
+#endif
+
+/*===========================================================================*/
+/* Module exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Array of the default commands.
+ */
+ShellCommand shell_local_commands[] = {
+#if SHELL_CMD_INFO_ENABLED == TRUE
+  {"info", cmd_info},
+#endif
+#if SHELL_CMD_SYSTIME_ENABLED == TRUE
+  {"systime", cmd_systime},
+#endif
+#if SHELL_CMD_MEM_ENABLED == TRUE
+  {"mem", cmd_mem},
+#endif
+#if SHELL_CMD_THREADS_ENABLED == TRUE
+  {"threads", cmd_threads},
+#endif
+#if SHELL_CMD_TEST_ENABLED == TRUE
+  {"test", cmd_test},
+#endif
+  {NULL, NULL}
+};
+
+/** @} */
diff --git a/os/various/shell/shell_cmd.h b/os/various/shell/shell_cmd.h
new file mode 100644
index 000000000..36e6c0728
--- /dev/null
+++ b/os/various/shell/shell_cmd.h
@@ -0,0 +1,106 @@
+/*
+    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+    Licensed 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.
+*/
+
+/**
+ * @file    shell_cmd.h
+ * @brief   Simple CLI shell common commands header.
+ *
+ * @addtogroup SHELL
+ * @{
+ */
+
+#ifndef _SHELLCMD_H_
+#define _SHELLCMD_H_
+
+/*===========================================================================*/
+/* Module constants.                                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module pre-compile time settings.                                         */
+/*===========================================================================*/
+
+#if !defined(SHELL_CMD_INFO_ENABLED) || defined(__DOXYGEN__)
+#define SHELL_CMD_INFO_ENABLED              TRUE
+#endif
+
+#if !defined(SHELL_CMD_SYSTIME_ENABLED) || defined(__DOXYGEN__)
+#define SHELL_CMD_SYSTIME_ENABLED           TRUE
+#endif
+
+#if !defined(SHELL_CMD_MEM_ENABLED) || defined(__DOXYGEN__)
+#define SHELL_CMD_MEM_ENABLED               TRUE
+#endif
+
+#if !defined(SHELL_CMD_THREADS_ENABLED) || defined(__DOXYGEN__)
+#define SHELL_CMD_THREADS_ENABLED           TRUE
+#endif
+
+#if !defined(SHELL_CMD_TEST_ENABLED) || defined(__DOXYGEN__)
+#define SHELL_CMD_TEST_ENABLED              TRUE
+#endif
+
+#if !defined(SHELL_CMD_TEST_WA_SIZE) || defined(__DOXYGEN__)
+#define SHELL_CMD_TEST_WA_SIZE              THD_WORKING_AREA_SIZE(256)
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+#if (SHELL_CMD_MEM_ENABLED == TRUE) && (CH_CFG_USE_MEMCORE == FALSE)
+#error "SHELL_CMD_MEM_ENABLED requires CH_CFG_USE_MEMCORE"
+#endif
+
+#if (SHELL_CMD_MEM_ENABLED == TRUE) && (CH_CFG_USE_HEAP == FALSE)
+#error "SHELL_CMD_MEM_ENABLED requires CH_CFG_USE_HEAP"
+#endif
+
+#if (SHELL_CMD_THREADS_ENABLED == TRUE) && (CH_CFG_USE_REGISTRY == FALSE)
+#error "SHELL_CMD_THREADS_ENABLED requires CH_CFG_USE_REGISTRY"
+#endif
+
+/*===========================================================================*/
+/* Module data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module macros.                                                            */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern ShellCommand shell_local_commands[];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/*===========================================================================*/
+/* Module inline functions.                                                  */
+/*===========================================================================*/
+
+#endif /* _SHELLCMD_H_ */
+
+/** @} */
diff --git a/testhal/STM32/STM32F7xx/USB_CDC/Makefile b/testhal/STM32/STM32F7xx/USB_CDC/Makefile
index c8262db2d..f94db3344 100644
--- a/testhal/STM32/STM32F7xx/USB_CDC/Makefile
+++ b/testhal/STM32/STM32F7xx/USB_CDC/Makefile
@@ -99,6 +99,8 @@ include $(CHIBIOS)/os/rt/rt.mk
 include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
 # Other files (optional).
 include $(CHIBIOS)/test/rt/test.mk
+include $(CHIBIOS)/os/hal/lib/streams/streams.mk
+include $(CHIBIOS)/os/various/shell/shell.mk
 
 # Define linker script file here
 LDSCRIPT= $(STARTUPLD)/STM32F746xG.ld
@@ -113,9 +115,8 @@ CSRC = $(STARTUPSRC) \
        $(PLATFORMSRC) \
        $(BOARDSRC) \
        $(TESTSRC) \
-       $(CHIBIOS)/os/various/shell.c \
-       $(CHIBIOS)/os/hal/lib/streams/memstreams.c \
-       $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
+       $(STREAMSSRC) \
+       $(SHELLSRC) \
        usbcfg.c main.c
 
 # C++ sources that can be compiled in ARM or THUMB mode depending on the global
@@ -147,7 +148,7 @@ ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
 
 INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
          $(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
-         $(CHIBIOS)/os/hal/lib/streams $(CHIBIOS)/os/various
+         $(STREAMSINC) $(SHELLINC)
 
 #
 # Project, sources and paths
diff --git a/testhal/STM32/STM32F7xx/USB_CDC/main.c b/testhal/STM32/STM32F7xx/USB_CDC/main.c
index b75c37cda..d703f52c5 100644
--- a/testhal/STM32/STM32F7xx/USB_CDC/main.c
+++ b/testhal/STM32/STM32F7xx/USB_CDC/main.c
@@ -31,59 +31,6 @@
 /*===========================================================================*/
 
 #define SHELL_WA_SIZE   THD_WORKING_AREA_SIZE(2048)
-#define TEST_WA_SIZE    THD_WORKING_AREA_SIZE(256)
-
-static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
-  size_t n, total, largest;
-
-  (void)argv;
-  if (argc > 0) {
-    chprintf(chp, "Usage: mem\r\n");
-    return;
-  }
-  n = chHeapStatus(NULL, &total, &largest);
-  chprintf(chp, "core free memory : %u bytes\r\n", chCoreGetStatusX());
-  chprintf(chp, "heap fragments   : %u\r\n", n);
-  chprintf(chp, "heap free total  : %u bytes\r\n", total);
-  chprintf(chp, "heap free largest: %u bytes\r\n", largest);
-}
-
-static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
-  static const char *states[] = {CH_STATE_NAMES};
-  thread_t *tp;
-
-  (void)argv;
-  if (argc > 0) {
-    chprintf(chp, "Usage: threads\r\n");
-    return;
-  }
-  chprintf(chp, "stklimit    stack     addr prio     state         name\r\n");
-  tp = chRegFirstThread();
-  do {
-    chprintf(chp, "%08lx %08lx %08lx %4lu %9s %12s\r\n",
-             (uint32_t)tp->stklimit, (uint32_t)tp->ctx.r13, (uint32_t)tp,
-             (uint32_t)tp->prio, states[tp->state],
-             tp->name == NULL ? "" : tp->name);
-    tp = chRegNextThread(tp);
-  } while (tp != NULL);
-}
-
-static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
-  thread_t *tp;
-
-  (void)argv;
-  if (argc > 0) {
-    chprintf(chp, "Usage: test\r\n");
-    return;
-  }
-  tp = chThdCreateFromHeap(NULL, TEST_WA_SIZE, chThdGetPriorityX(),
-                           TestThread, chp);
-  if (tp == NULL) {
-    chprintf(chp, "out of memory\r\n");
-    return;
-  }
-  chThdWait(tp);
-}
 
 /* Can be measured using dd if=/dev/xxxx of=/dev/null bs=512 count=10000.*/
 static void cmd_write(BaseSequentialStream *chp, int argc, char *argv[]) {
@@ -126,9 +73,6 @@ static void cmd_write(BaseSequentialStream *chp, int argc, char *argv[]) {
 }
 
 static const ShellCommand commands[] = {
-  {"mem", cmd_mem},
-  {"threads", cmd_threads},
-  {"test", cmd_test},
   {"write", cmd_write},
   {NULL, NULL}
 };
@@ -218,8 +162,7 @@ int main(void) {
                                     shellThread, (void *)&shell_cfg1);
     }
     else if (chThdTerminatedX(shelltp)) {
-      chThdWait(shelltp);
-      chHeapFree(chthdGetStackLimitX(shelltp));
+      chThdFreeToHeap(shelltp);
       shelltp = NULL;           /* Triggers spawning of a new shell.        */
     }
 #if 0
-- 
cgit v1.2.3