221 lines
8.4 KiB
ReStructuredText
221 lines
8.4 KiB
ReStructuredText
========================*
|
|
Customizing the NuttShell
|
|
========================*
|
|
|
|
**Overview.** The NuttShell (NSH) is a simple shell application that may
|
|
be used with NuttX. It supports a variety of commands and is (very)
|
|
loosely based on the Bash shell and the common utilities used with Bash
|
|
shell programming. The paragraphs in this appendix will focus on
|
|
customizing NSH: Adding new commands, changing the initialization
|
|
sequence, etc.
|
|
|
|
The NSH Library and NSH Initialization
|
|
======================================
|
|
|
|
**Overview.** NSH is implemented as a library that can be found at
|
|
``apps/nshlib``. As a library, it can be custom built into any
|
|
application that follows the NSH initialization sequence described
|
|
below. As an example, the code at ``apps/examples/nsh/nsh_main.c``
|
|
illustrates how to start NSH and the logic there was intended to be
|
|
incorporated into your own custom code. Although code was generated
|
|
simply as an example, in the end most people just use this example code
|
|
as their application ``main()`` function. That initialization performed
|
|
by that example is discussed in the following paragraphs.
|
|
|
|
NSH Initialization sequence
|
|
---------------------------
|
|
|
|
The NSH start-up sequence is very simple. As an example, the code at
|
|
``apps/system/nsh/nsh_main.c`` illustrates how to start NSH. It simple
|
|
does the following:
|
|
|
|
#. This function calls ``nsh_initialize()`` which initializes the NSH
|
|
library. ``nsh_initialize()`` is described in more detail below.
|
|
|
|
#. If the Telnetconsole is enabled, it calls ``nsh_telnetstart()`` which
|
|
resides in the NSH library. ``nsh_telnetstart()`` will start the
|
|
Telnet daemon that will listen for Telnet connections and start
|
|
remote NSH sessions.
|
|
|
|
#. If a local console is enabled (probably on a serial port), then
|
|
``nsh_consolemain()`` is called. ``nsh_consolemain()`` also resides
|
|
in the NSH library. ``nsh_consolemain()`` does not return so that
|
|
finished the entire NSH initialization sequence.
|
|
|
|
``nsh_initialize()``
|
|
--------------------
|
|
|
|
The NSH initialization function, ``nsh_initialize()``, be found in
|
|
``apps/nshlib/nsh_init.c``. It does only four things:
|
|
|
|
#. ``nsh_romfsetc()``: If so configured, it executes NSH system init and
|
|
start-up script that can be found at ``/etc/init.d/rc.sysinit`` and
|
|
``/etc/init.d/rcS`` in the target file system. The ``nsh_romfsetc()``
|
|
function can be found in ``apps/nshlib/nsh_romfsetc.c``.
|
|
This function will (1) register a ROMFS file system, then (2) mount
|
|
the ROMFS file system. ``/etc`` is the default location where a
|
|
read-only, ROMFS file system is mounted by ``nsh_romfsetc()``.
|
|
|
|
The ROMFS image is, itself, just built into the firmware. By default,
|
|
this ``rc.sysinit`` system init script contains the following logic::
|
|
|
|
# Create a RAMDISK and mount it at XXXRDMOUNTPOINTXXX
|
|
|
|
mkrd -m XXXMKRDMINORXXX -s XXMKRDSECTORSIZEXXX XXMKRDBLOCKSXXX
|
|
mkfatfs /dev/ramXXXMKRDMINORXXX
|
|
mount -t vfat /dev/ramXXXMKRDMINORXXX XXXRDMOUNTPOINTXXX
|
|
|
|
Where the ``XXXX*XXXX`` strings get replaced in the template when the
|
|
ROMFS image is created:
|
|
|
|
- ``XXXMKRDMINORXXX`` will become the RAM device minor number.
|
|
Default: 0
|
|
|
|
- ``XXMKRDSECTORSIZEXXX`` will become the RAM device sector size
|
|
|
|
- ``XXMKRDBLOCKSXXX`` will become the number of sectors in the
|
|
device.
|
|
|
|
- ``XXXRDMOUNTPOINTXXX`` will become the configured mount point.
|
|
Default: ``/etc``
|
|
|
|
By default, the substituted values would yield an ``rc.sysinit`` file like::
|
|
|
|
# Create a RAMDISK and mount it at /tmp
|
|
|
|
mkrd -m 1 -s 512 1024
|
|
mkfatfs /dev/ram1
|
|
mount -t vfat /dev/ram1 /tmp
|
|
|
|
This script will, then:
|
|
|
|
- Create a RAMDISK of size 512*1024 bytes at ``/dev/ram1``,
|
|
|
|
- Format a FAT file system on the RAM disk at ``/dev/ram1``, and
|
|
then
|
|
|
|
- Mount the FAT file system at a configured mountpoint, ``/tmp``.
|
|
|
|
This ``rc.sysinit.template`` template file can be found at
|
|
``apps/nshlib/rc.sysinit.template``. The resulting ROMFS file system can be
|
|
found in ``apps/nshlib/nsh_romfsimg.h``.
|
|
|
|
#. ``board_app_initialize()``: Next any architecture-specific NSH
|
|
initialization will be performed (if any). For the STM3240G-EVAL,
|
|
this architecture specific initialization can be found at
|
|
``boards/arm/stm32/stm3240g-eval/src/stm32_appinit.c``. This it does
|
|
things like: (1) Initialize SPI devices, (2) Initialize SDIO, and (3)
|
|
mount any SD cards that may be inserted.
|
|
|
|
#. ``nsh_netinit()``: The ``nsh_netinit()`` function can be found in
|
|
``apps/nshlib/nsh_netinit.c``.
|
|
|
|
#. The start-up script ``rcS`` is executed after the system-init script
|
|
to startup some application and other system service.
|
|
|
|
This ``rcS`` template file can be found at
|
|
``apps/nshlib/rcS.template``. The resulting ROMFS file system can be
|
|
found in ``apps/nshlib/nsh_romfsimg.h``.
|
|
|
|
NSH Commands
|
|
============
|
|
|
|
**Overview.** NSH supports a variety of commands as part of the NSH
|
|
program. All of the NSH commands are listed in the NSH documentation
|
|
`above <#cmdoverview>`__. Not all of these commands may be available at
|
|
any time, however. Many commands depend upon certain NuttX configuration
|
|
options. You can enter the help command at the NSH prompt to see the
|
|
commands actual available:
|
|
|
|
For example, if network support is disabled, then all network-related
|
|
commands will be missing from the list of commands presented by
|
|
'``nsh> help``'. You can see the specific command dependencies in the
|
|
table `above <#cmddependencies>`__.
|
|
|
|
Adding New NSH Commands
|
|
-----------------------
|
|
|
|
New commands can be added to the NSH very easily. You simply need to add
|
|
two things:
|
|
|
|
#. The implementation of your command, and
|
|
|
|
#. A new entry in the NSH command table
|
|
|
|
**Implementation of Your Command.** For example, if you want to add a
|
|
new a new command called ``mycmd`` to NSH, you would first implement the
|
|
``mycmd`` code in a function with this prototype:
|
|
|
|
.. code-block:: c
|
|
|
|
int cmd_mycmd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv);
|
|
|
|
The ``argc`` and ``argv`` are used to pass command line arguments to the
|
|
NSH command. Command line parameters are passed in a very standard way:
|
|
``argv[0]`` will be the name of the command, and ``argv[1]`` through
|
|
``argv[argc-1]`` are the additional arguments provided on the NSH
|
|
command line.
|
|
|
|
The first parameter, ``vtbl``, is special. This is a pointer to
|
|
session-specific state information. You don't need to know the contents
|
|
of the state information, but you do need to pass this ``vtbl`` argument
|
|
when you interact with the NSH logic. The only use you will need to make
|
|
of the ``vtbl`` argument will be for outputting data to the console. You
|
|
don't use ``printf()`` within NSH commands. Instead you would use:
|
|
|
|
.. code-block:: c
|
|
|
|
void nsh_output(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...);
|
|
|
|
So if you only wanted to output "Hello, World!" on the console, then
|
|
your whole command implementation might be:
|
|
|
|
.. code-block:: c
|
|
|
|
int cmd_mycmd(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
|
|
{
|
|
nsh_output(vtbl, "Hello, World!");
|
|
return 0;
|
|
}
|
|
|
|
The prototype for the new command should be placed in
|
|
``apps/examples/nshlib/nsh.h``.
|
|
|
|
**Adding You Command to the NSH Command Table**. All of the commands
|
|
support by NSH appear in a single table called:
|
|
|
|
.. code-block:: c
|
|
|
|
const struct cmdmap_s g_cmdmap[]
|
|
|
|
That table can be found in the file
|
|
``apps/examples/nshlib/nsh_parse.c``. The structure ``cmdmap_s`` is also
|
|
defined in ``apps/nshlib/nsh_parse.c``:
|
|
|
|
.. code-block:: c
|
|
|
|
struct cmdmap_s
|
|
{
|
|
const char *cmd; /* Name of the command */
|
|
cmd_t handler; /* Function that handles the command */
|
|
uint8_t minargs; /* Minimum number of arguments (including command) */
|
|
uint8_t maxargs; /* Maximum number of arguments (including command) */
|
|
const char *usage; /* Usage instructions for 'help' command */
|
|
};
|
|
|
|
This structure provides everything that you need to describe your
|
|
command: Its name (``cmd``), the function that handles the command
|
|
(``cmd_mycmd()``), the minimum and maximum number of arguments needed by
|
|
the command, and a string describing the command line arguments. That
|
|
last string is what is printed when enter "``nsh> help``".
|
|
|
|
So, for you sample command, you would add the following the to the
|
|
``g_cmdmap[]`` table:
|
|
|
|
.. code-block:: c
|
|
|
|
{ "mycmd", cmd_mycmd, 1, 1, NULL },
|
|
|
|
This entry is particularly simply because ``mycmd`` is so simple. Look
|
|
at the other commands in ``g_cmdmap[]`` for more complex examples.
|