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.
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)
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();
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);
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.