Introduction


Typically, there is only one iop::HealthReporter service per JAUS node which reports the health of every JAUS component on that node. In this approach, implementing the HealthReporter service can be tricky if there are multiple components on a node, since it requires sharing information from each component back to the component that houses the HealthReporter service. In addition, if a client sends the UpdateHealthReporter message, the HealthReporter service must trigger a commanded built-in test (CBIT) for all the components on the node. Figure 1 below gives a simple notional block diagram of the layout.


 

 

Figure 1. Notional Block Diagram of a single HealthReporter service per JAUS Node




In order to facilitate this design there must be some communication between the components to exchange health information and trigger CBIT. The mechanism for doing so will depend on your JAUS node design. 


In the typical OpenJAUS design approach, a JAUS node is a single application with each component being a separate thread (really a group of threads) running inside that single application. With that design in mind, we have an implementation of the HealthReporter service which provides all the needed hooks discussed above. The implementation is provided using the OjHealthReporter class.



OjHealthReporter Implementation


The OjHealthReporter class uses the Mediator design pattern to facilitate communication between components. A HealthManager object acts as the Mediator, to which components can add themselves and update their health status, and the HealthReporter service can query to report the health of each component as needed. Figure 2 shows how the HealthManager interacts with the components.



 

 


Figure 2. Block Diagram of the OjHealthReporter and the HealthManager



The HealthManager Class(es)



openjaus::model::HealthManager


This is the main class which is used to connect the OjHealthReporter service implementation to the different components. The same HealthManager instance must be used by each component to have everything work correctly so a Singleton object pointer is provided and can be obtained by:


openjaus::model::HealthManager* healthManager = openjaus::model::HealthManager::Instance();



openjaus::model::ComponentHealthManager


This class encapsulates the health for an individual component. A ComponentHealthManager object pointer is obtained by adding an openjaus::model::Component to the HealthManager object. This hooks everything together so that the component health can be correctly reported by the OjHealthReporter. This is typically called from inside a derived Component class (see HowTo: Create a Component) like this:


openjaus::model::ComponentHealthManager* componentHealthManager = healthManager.addComponent(this);



openjaus::model::ServiceHealthManager


This class is used to update the health on a individual service or group of services under a specific component. Because the same service can exist under different components on the same node, a ServiceHealthManager object pointer can only be obtained from a ComponenHealthManager object. That associates the ServiceHealthManager with the specific component. 


To obtain a ServiceHealthManager object pointer you need to tell the ComponentHealthManager which service or services you want to associate with that ServiceHealthManager object.


If only a single service needs to be associated with the ServiceHealthManager, a single service URI can be provided:


openjaus::model::ServiceHealthManager* softwareVersionHealthManager = componentHealthManager->getServiceHealthManager(openjaus::iop_v3::services::SoftwareVersionReporting::uri());


If multiple service needs to be associated with the ServiceHealthManager, then a std::vector of service URIs need to be provided:


std::vector<std::string> serviceUris;
serviceUris.push_back(openjaus::manipulator_v2_0::services::PrimitivePanTilt::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PrimitivePanTilt::uri());
serviceUris.push_back(openjaus::iop_v3::services::ExtendedPrimitivePanTilt::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PanTiltSpecification::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PanTiltJointPositionSensor::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PanTiltJointVelocitySensor::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PanTiltMotionProfile::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PanTiltJointPositionDriver::uri());
serviceUris.push_back(openjaus::manipulator_v2_0::services::PanTiltJointVelocityDriver::uri());

openjaus::model::ServiceHealthManager* panTiltHealthManager = componentHealthManager->getServiceHealthManager(serviceUris);


Once a ServiceHealthManager has been created, the services associated with that object cannot be changed. You would need to destroy the object and create a new one to change the service associations.



Updating the Health Status


Once a ServiceHealthManager has been created the health status of the services associated with the ServiceHealthManager can be updated using the updateStatus() and clearStatus() methods.


The reported health of the SoftwareVersionReporting service is updated:


// If error loading software version data
softwareVersionHealthManager->updateStatus(
                openjaus::model::ServiceHealthStatus::SEVERITY_WARN,
                openjaus::model::ServiceHealthStatus::CODE_FILESYS,
                "SoftwareVersions not loaded correctly. Versions not available.");



The reported health of the all the PanTilt services (PrimitivePanTilt, ExtendedPrimitivePanTilt, PanTiltJointPositionSensor, etc) is updated:


// If error detected with the pan tilt hardware
panTiltHealthManager ->updateStatus(
                openjaus::model::ServiceHealthStatus::SEVERITY_ERR,
                openjaus::model::ServiceHealthStatus::CODE_ACTUATOR,
                "Can no longer communicate the PanTilt.");



The reported error of the all the PanTilt services is cleared


// If pan tilt error has been cleared
panTiltHealthManager ->clearStatus();



Triggering Commanded Built-In Test (CBIT)


Each HealthManager class provides an addOnCommandedUpdateCallback method which can be used to register a callback to be called when the UpdateHealthReporter message is called. The class on which you register the callback makes no functional difference and will depend on your specific implementation. 


NOTE:  Registered callbacks should NOT block. If they do, they will prevent any other JAUS messages from being processed.