OpenJAUS

Creating a Component

An essential part of implementing a JAUS system is to develop software components. JAUS components define a logical boundary that contains system services. Services are stand alone tasks designed to perform a specific function and they have a well defined message interface. In the JAUS RA 3.3 components provide at least one service, and a service is simply defined as a set of input and output messages. In addition to the message service interface, JAUS components typically implement an internal state machine that is used to perform and manage its intended function.

An OpenJAUS component is implemented by calling the component framework library. The library contains a set of C functions used to create, setup, manage and destroy the component. The first step in this process is to create a program that includes the standard OpenJAUS header files. The component library is included with openJaus.h, and jaus.h is needed to access JAUS message functions.
#include <jaus.h>      // Header file for JAUS types, structs and messages
#include <openJaus.h>  // Header file for the OpenJAUS specific C/C++ code base
All of the component library functions begin with the prefix ojCmpt and are designed to work with the OjCmpt data type, which stores a reference to the component. To obtain an OjCmpt type and generate the JAUS component, the ojCmptCreate() function is called. The function has three arguments: first, a pointer to a character string containing the component's name identifier, then an integer numeric identifier for the component, and finally the double value desired rate in Hz for which the component's state machine will execute. The function generates the component data structure and then checks into the OpenJAUS Node Manager, which must be running at the time of the call, otherwise the component will fail and return NULL. This example shows how a JAUS Global Pose Sensor might be created.
// Variable that will store the component reference
OjCmpt myGpos;

// Create the component with name "My GPOS", id 38, and state machine runs at 1.0 Hz
myGpos = ojCmptCreate("My GPOS", JAUS_GLOBAL_POSE_SENSOR, 1.0);

// Test for failed Node Manager check-in of component
if(myGpos == NULL)
{
	// Exit program
	printf("Error Starting Component\n");
	return 1;
}
A this point the component is created and communicating with the node manager, but its state machine is not running yet. Before the state machine is started, the component services and callback functions must first be setup. The message service interface for the component is defined by calling the ojCmptAddService() methods. A service interface is generated by adding its int value to the component. Then input and output messages are attached to that service by referencing the component and int service value. The messages are defined by their command code and presence vector value. This example shows how a service is attached to the GPOS component created above:
// Add a new service to the component, with one input and one output message
ojCmptAddService(myGpos, JAUS_GLOBAL_POSE_SENSOR);
ojCmptAddServiceInputMessage(myGpos, JAUS_GLOBAL_POSE_SENSOR, JAUS_QUERY_GLOBAL_POSE, 0xFF);
ojCmptAddServiceOutputMessage(myGpos, JAUS_GLOBAL_POSE_SENSOR, JAUS_REPORT_GLOBAL_POSE, 0xFF);
The next step is to setup the state machine, message callbacks, and supported service connections. For this tutorial, only the state machine setup is shown. See the tutorials on sending and receiving messages, and supporting service connections for how to setup these capabilities.

The component's state machine works by calling a function callback method upon each interval of the timer frequency set at the create step. All component states are indexed with a int value, and an OpenJAUS component is allowed to have up to 32 states (Note: Only six states, values 0 through 5, are defined by JAUS. See jausState.h for their enumeration. If your software uses state values greater than 5, the default message response to a JAUS_QUERY_COMPONENT_STATUS message will report an invalid state. You must override this default behavior in order to report a meaningful JAUS state. See sending and receiving messages for how to do this.) Usually only a few states are actually needed. Fewer states keeps the component functionality simple and much easier to manage its expected behavior. A function pointer to each callback method must be registered with the component for the state machine to work correctly. The ojCmptSetStateCallback() function is used to do this. Its arguments are: the OjCmpt reference, and then the int numeric value for the state callback being registered, finally a function pointer to the state callback is given. State function pointers must match the prototype: "void function(OjCmpt);". For the myGpos example, the Ready state would be setup as follows:
// Register function callback for the ready state
ojCmptSetStateCallback(myGpos, JAUS_READY_STATE, gposReadyState);
This statement would depend on either the gposReadyState function itself or its function prototype appearing prior to this function call in the code. This is how the above example's prototype would have been defined somewhere above in the code:
// Function prototype for My GPOS ready state callback routine
void gposReadyState(OjCmpt myGpos);
Upon execution of the state machine, the current state value must be specified to the component. The state is set by calling the ojCmptSetState() function, and passing it the numeric value of the current desired state. If no value is ever specified, the component remains in an undefined state mode, and no callback functions are executed. In this example the myGpos state would be set as follows:
// Set the current component state to JAUS_READY_STATE
ojCmptSetState(myGpos, JAUS_READY_STATE);
The last step after setting up all of the initial component information is to begin running the state machine. This is done by calling ojCmptRun(), which creates the main component thread that is used to execute the state machine and message processing callbacks. This thread manages itself in the background.
// Start the component state machine and message processing
ojCmptRun(myGpos);	

// Wait for user input
getchar(); 
The component should now be running and sending heartbeats to the Node Manager in order to maintain its connection. Typically a main application would provide some user interface to the component and wait for the user to instruct the software to shutdown. For this example, a simple wait is implemented by calling getchar(). When the user hits enter the program continues and then proceeds to the last step of destroying the component. Prior to termination the component is actively calling the gposReadyState() callback. In order to demonstrate this, the callback performs a printf() to display a string to the user. The callback function implementation is shown below:
// Ready state callback function
void gposReadyState(OjCmpt myGpos)
{
	printf("My JAUS Component Hello World\n");
}
The ojCmptDestroy() function is used to terminate the component threads, checkout of the Node Manager, and free any allocated memory. The only argument to this function is the OjCmpt being destroyed.
// Stop and destroy the component
ojCmptDestroy(myGpos); 
Download the code for this example below.
myGpos.c

 

© OpenJAUS.com 2008
All Rights Reserved