========================* 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. Thensh_romfsetc()
function can be found inapps/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 bynsh_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 XXXRDMOUNTPOINTXXXWhere 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 /tmpThis 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 thenMount the FAT file system at a configured mountpoint,
/tmp
.This
rc.sysinit.template
template file can be found atapps/nshlib/rc.sysinit.template
. The resulting ROMFS file system can be found inapps/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 atboards/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()
: Thensh_netinit()
function can be found inapps/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 atapps/nshlib/rcS.template
. The resulting ROMFS file system can be found inapps/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. 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.
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:
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:
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:
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:
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
:
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:
{ "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.