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:

DAT defined commands

Shell Command Interface

Commands are added to the shell either at startup (DAT commands, above) or by the user with addCommand. All DAT 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.

  • No labels