Main Page | Modules | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

Basic module example: PrintModule

This section describes the details of implementing a simple RHexLib program which periodically displays the encoder counters.

The PrintModule Class

In RHexLib, any task that needs to be performed periodically is defined as a Module, more specifically as a class derived from the Module abstract base class. Below is a definition of the PrintModule class, which encapsulates the task of periodically reading and printing the encoder counter values.

class PrintModule : public Module {

public:
  PrintModule ( void ) : Module( "print", 0, false, false ) { };

  void init( void ) { };
  void uninit( void ) { };
  void activate( void );
  void deactivate( void );
  void update( void );

};

Note that each class derived from the virtual base class Module must define five methods: init, uninit, activate, deactivate and update. These methods provide a a standard interface to the module manager which, among other tasks, keeps a list of all modules, manages their states, and calls the above methods at appropriate times. In the case of PrintModule, the uninit method does not do anything, the rest of the methods are defined below.

An important detail to note is that the Module class constructor takes four arguments. The first two determine the name and index of the module, which are used together to uniquely identify each module in the system. The last two arguments determine the type of the module and are explained in later chapters of this manual.

The init method

Module::init is called whenever the module is added to the module manager's list with a call to the function MMAddModule(). The init method is usually responsible for initializing related hardware components and finding components and other modules that are needed for the module's operation. In our example, no initializations are required, so the init method is empty.

The activate method

Module::activate is called whenever the module is activated by the module manager via a call to either MMActivateModule() or the first call to MMGrabModule(). This changes the the module from the INACTIVE state to the ACTIVE state, which means that the module manager will begin to periodically call the update method of the module.

Activating a module usually involves making sure that all the components needed for the task are active and operational. Moreover, necessary initializations of the components must also be performed. For our example, the PrintModule will enable all the encoders using the hardware interface.

void PrintModule::activate( void ) {
  int axis;

  for ( axis = 0; axis < 6; axis++ )
    EncoderHW::instance()->enable( axis );
}

An important detail to note is the way hardware components are accessed. Interfaces to hardware components are defined as abstract base classes (such as EncoderHW, DCMotorHW, DriveHW etc.). Each of these classes internally maintains a single instance of an actual implementation, which is initialized by the particular hardware library to be used. For those of you who are familiar with design patterns, this corresponds to a singleton design pattern. To be able to use a particular hardware component, the corresponding header file ("hardware/EncoderHW.hh" in this case) must be included.

As you may have guessed, the instance() method of such classes returns a pointer to the singleton instance of the corresponding hardware component, which can then be used to access the hardware functionality. A more detailed treatment of how hardware access is handled by RhexLib can be found in Hardware abstraction layer .

The deactivate method

Module::deactivate is called whenever the module is deactivated through a call to either MMDeactivateModule() or the last call to MMReleaseModule(). This puts the module in the INACTIVE state, which means that the update method of the module will not be called anymore.

For our example, upon deactivation, the PrintModule will disable all the encoders using the hardware interface.

void PrintModule::deactivate( void ) {
  int axis;

  for ( axis = 0; axis < 6; axis++ )
    EncoderHW::instance()->disable( axis );
}

The update method

Module::update is where the core functionality of a module is defined. When a module is in the ACTIVE state, its update function is called periodically by the module manager.

Our example module, the PrintModule, will read the encoders and print their contents in its update method. Moreover, it will also be responsible for detecting keyboard input and exiting the program.

void  PrintModule::update ( void ) {
  int axis;

  printf( "Encoders: " );

  for ( axis = 0; axis < 6; axis++ )
    printf( "0x%04x, ", EncoderHW::instance()->read( axis ) );

  printf( "\n" );

  if ( kbhit() ) {
    MMMessage( "User interrupt: Shutting down!\n" );
    MMPowerOff( );
  }
}

Using PrintModule in a program

What makes modules operational in RHexLib is the Module Manager. In order to be operational, modules must be created as instatiations of the class, and the module manager must be informed of its presence through the MMAddModule() library call. Moreover, it needs to be activated through the MMActivateModule() or MMGrabModule() library functions in order for its update function to start being called periodically.

The library function MMMainLoop() is the main entry point to the module manager, and only returns when the program is about to terminate. It is usually called once from main(), after all the desired modules are created and added to the module manager's list. Once this function is called, the module manager takes control and handles the periodic issues of module updates as well as other timing tasks. Following a call to MMMainLoop(), the only way to exit the program is through the MMPowerOff function, from within one of the module methods.

As such, there is a very typical way in which RHexLib programs are built. The following program is the main entry point to our small example and demonstrates how things are setup in a typical RHexLib program..

#include "ModuleManager.hh"

int main( void ) {

  PrintModule pr; // Create an instance of the PrintModule module.

  // Initialize whichever hardware library we are linked against
  initHardware();

  // Add and activate the print module
  MMAddModule( &pr, 10, 0, 10 );
  MMActivateModule( &pr );

  // Call the Module Manager main loop
  MMMainLoop();

  // Cleanup underlying hardware before we exit
  cleanupHardware();

  // Let the module manager do its final cleanup
  MMShutdown();

  return 0;
}

As this code segment shows, the typical structure of main() is as follows:

During the call to MMMainLoop(), the module methods will determine the flow of the execution. Note that at least one module needs to be activated before MMMainLoop is called. Otherwise, the program will be stuck in an infinite loop, and no module updates will take place.

An important detail is that the parameters of a module related to the scheduling of its updates are determined by the arguments to the MMAddModule() function call. It is hence possible to configure the period, the starting time offset and the update order (in case of multiple updates scheduled at the same time) of each module.


RHexLib Reference Documentation