The code for the DAT interface to the RTEMS shell is located in the rce/shell
directory. All interaction with the RTEMS operating system is encapsulated away from the user inside the interface. Portions of the shell have been customized by the DAT group, and these customizations are listed below.
RTEMS Commands
The commands that the RTEMS 4.10.0 base shell provides are:
- alias - Add an alias for an existing command
- blksync - sync the block driver
- cat - display file contents
- cd - alias for chdir
- chdir - change the current directory
- chmod - change permissions of a file
- chroot - change the root directory
- config - show the system configuration.
- cp - copy files
- cpuuse - print or reset per thread cpu usage
- date - print or set system date
- dd - convert and copy a file
- debugrfs - debug RFS file system
- dir - alias for ls
- dname - displays information about named drivers
- driver - display the rtems device driver table
- echo - echo a string
- exit - exit the shell
- extension - display information about extensions
- fdisk - format disk
- getenv - get environment variable
- halt - Shutdown the system
- hexdump - ascii/dec/hex/octal dump
- id - show user ID
- ifconfig - configure a network interface
- itask - list init tasks for the system
- ln - make links
- logoff - exit the shell
- ls - list files in the directory
- malloc - obtain information on C program heap
- mdump - display contents of memory
- medit - modify contents of memory
- mfill - file memory with pattern
- mkdir - create a directory
- mknod - make device special file
- mkrfs - format RFS file system
- mmove - move contents of memory
- mount - mount disk
- mv - move files
- netstats - obtain network statistics
- object - display information about rtems objects
- part - display information about partitions
- perioduse - print or reset per period usage
- pthread - display information about POSIX threads
- pwd - print work directory
- queue - display information about message queues
- region - display information about regions
- rm - remove files
- rmdir - remove empty directories
- route - show or manipulate the ip routing table
- rtc - configure the RTC driver
- sema - display information about semaphores
- setenv - set environment variable
- sleep - delay for a time
- stackuse - print per thread stack usage
- task - display information about tasks
- time - time a command execution
- tty - show tty name
- umask - set file mode creation mask
- unmount - unmount disk
- unsetenv - unset ditto
- wdump - display contents of memory (word)
- whoami - print userID
- wkspace - display information on executive workspace
DAT defined commands
- burnSystem - burn a SYSTEM container to flash (To be deprecated)
- burnTask - burn a TASK container to flash
- runTask - load and run a module as a task
- freeBlocks - dump the block usage map
- fsDump - dump an index of the flash filesystem. Developer tool
- lsSystem - display SYSTEM images
- lsTask - display TASK images
- reboot - reboot the board
- rmContainer - Delete a container
- stopTask - send a stop message to a task
- syslog - dump the in-memory system log
- addCommand - add an arbitrary command to the shell (see below)
Shell Command Interface
Commands are added to the shell either at startup (CTK commands, above) or by the user with addCommand
. All CTK and user defined commands are based on the Command
class defined in rce/shell/Command.hh
. The public interface to Command
is:
namespace RCE { namespace Shell { class Command { public: typedef int (*MainFunc)(int, char**); public: Command(std::string name, std::string topic, std::string alias = ""); virtual ~Command(); std::string name(); std::string topic(); std::string alias(); virtual std::string usage() = 0; virtual MainFunc main() = 0; void initialize(); }; } }
The user defines their own command by implementing the pure virtual functions. A trivial example is below. This adds the command newCommand
to the help namespace misc
. The user provides a "MainFunc" type function (in this case NewCommand_main
) and returns this function from NewCommand::main()
.
#include "rce/shell/Command.hh" namespace FOO { using RCE::Shell::Command; class NewCommand : public Command { public: NewCommand(); virtual ~NewCommand() {} virtual std::string usage(); virtual MainFunc main(); }; int NewCommand_main(int argc, char** argv) { printf("This is a test of the new command\n"); return 0; } NewCommand::NewCommand() : Command("newCommand", "misc") {} std::string NewCommand::usage() { static std::string u = " newCommand # Do nothing but print a message\n"; return u; } Command::MainFunc NewCommand::main() { return NewCommand_main; } }
The next step is to make this easily viewable from the dynamic linker. By default, the addCommand
command will look for the entry point addCommands
in the user's module and attempt to execute it. For the above example, the code looks like this:
extern "C" { void EXPORT addCommands(int unused) { // Example of dynamic adding a new command. // the user must first instantiate, then initialize NewCMD::NewCommand cmd; cmd.initialize(); } }
Users can use any arbitrary name for this entry point.
The last step is to compile it into a module and add it to the shell. The shell syntax for adding a command is:
addCommand [-e entryPoint] <path_to_module>
where the -e option is used when the entry point is not addCommands
.
Note: When adding from multiple modules, each module's entry point must be distinct. Otherwise, the dynamic linker will complain about duplicate symbols, and the command won't be added correctly.