This sample application demonstrates how to configure and acquire sensor data. The sample application also shows how to acquire data from the same sensor with different configurations
1. Get sensor factory instance
auto &sensorFactory = telux::sensor::SensorFactory::getInstance();
2. Prepare a callback that is invoked when the sensor sub-system initialization is complete
std::promise<telux::common::ServiceStatus> p;
auto initCb = [&p](telux::common::ServiceStatus status) {
std::cout << "Received service status: " << static_cast<int>(status) << std::endl;
p.set_value(status);
};
3. Get the sensor manager. If initialization fails, perform necessary error handling
std::shared_ptr<telux::sensor::ISensorManager> sensorManager
= sensorFactory.getSensorManager(initCb);
if (sensorManager == nullptr) {
std::cout << "sensor manager is nullptr" << std::endl;
exit(1);
}
std::cout << "obtained sensor manager" << std::endl;
4. Wait until initialization is complete
p.get_future().get();
if (sensorManager->getServiceStatus() != telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << "Sensor service not available" << std::endl;
exit(1);
}
5. Get information regarding available sensors in the system
std::cout << "Sensor service is now available" << std::endl;
std::vector<telux::sensor::SensorInfo> sensorInfo;
telux::common::Status status = sensorManager->getAvailableSensorInfo(sensorInfo);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get information on available sensors" << static_cast<int>(status)
<< std::endl;
exit(1);
}
std::cout << "Received sensor information" << std::endl;
for (auto info : sensorInfo) {
printSensorInfo(info);
}
6. Request the ISensorManager for the desired sensor
std::shared_ptr<telux::sensor::ISensorClient> lowRateSensorClient;
std::cout << "Getting sensor: " << name << std::endl;
status = sensorManager->getSensor(lowRateSensorClient, name);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get sensor: " << name << std::endl;
exit(1);
}
7. Create and register a sensor event listener for configuration updates and sensor events
The event listener extends the ISensorEventListener to receive notification about configuration and sensor events.
class SensorEventListener : public telux::sensor::ISensorEventListener {
public:
SensorEventListener(std::string name, std::shared_ptr<telux::sensor::ISensorClient> sensor)
: name_(name)
, sensorClient_(sensor)
, totalBatches_(0) {
}
virtual void onEvent(std::shared_ptr<std::vector<telux::sensor::SensorEvent>> events) override {
PRINT_NOTIFICATION << "(" << name_ << "): Received " << events->size()
<< " events from sensor: " << sensorClient_->getSensorInfo().name
<< std::endl;
for (telux::sensor::SensorEvent s : *(events.get())) {
printSensorEvent(s);
}
++totalBatches_;
if (totalBatches_ > TOTAL_BATCHES_REQUIRED) {
totalBatches_ = 0;
std::thread t([&] {
sensorClient_->deactivate();
sensorClient_->configure(sensorClient_->getConfiguration());
sensorClient_->activate();
});
t.detach();
}
}
virtual void onConfigurationUpdate(telux::sensor::SensorConfiguration configuration) override {
PRINT_NOTIFICATION << "(" << name_ << "): Received configuration update from sensor: "
<< sensorClient_->getSensorInfo().name << ": ["
<< configuration.samplingRate << ", " << configuration.batchCount << " ]"
<< std::endl;
}
private:
bool isUncalibratedSensor(telux::sensor::SensorType type) {
return ((type == telux::sensor::SensorType::GYROSCOPE_UNCALIBRATED)
|| (type == telux::sensor::SensorType::ACCELEROMETER_UNCALIBRATED));
}
void printSensorEvent(telux::sensor::SensorEvent &s) {
telux::sensor::SensorInfo info = sensorClient_->getSensorInfo();
if (isUncalibratedSensor(sensorClient_->getSensorInfo().type)) {
PRINT_NOTIFICATION << ": " << sensorClient_->getSensorInfo().name << ": " << s.timestamp
<< ", " << s.uncalibrated.data.x << ", " << s.uncalibrated.data.y
<< ", " << s.uncalibrated.data.z << ", " << s.uncalibrated.bias.x
<< ", " << s.uncalibrated.bias.y << ", " << s.uncalibrated.bias.z
<< std::endl;
} else {
PRINT_NOTIFICATION << ": " << sensorClient_->getSensorInfo().name << ": " << s.timestamp
<< ", " << s.calibrated.x << ", " << s.calibrated.y << ", "
<< s.calibrated.z << std::endl;
}
}
std::string name_;
std::shared_ptr<telux::sensor::ISensorClient> sensorClient_;
uint32_t totalBatches_;
};
Create a event listener and register it with the sensor.
std::shared_ptr<SensorEventListener> lowRateSensorClientEventListener
= std::make_shared<SensorEventListener>("Low-rate", lowRateSensorClient);
lowRateSensorClient->registerListener(lowRateSensorClientEventListener);
8. Configure the sensor with required configuration setting the necessary validityMask
telux::sensor::SensorConfiguration lowRateConfig;
lowRateConfig.samplingRate = getMinimumSamplingRate(lowRateSensorClient->getSensorInfo());
lowRateConfig.batchCount = lowRateSensorClient->getSensorInfo().maxBatchCountSupported;
std::cout << "Configuring sensor with samplingRate, batchCount [" << lowRateConfig.samplingRate
<< ", " << lowRateConfig.batchCount << "]" << std::endl;
lowRateConfig.validityMask.set(telux::sensor::SensorConfigParams::SAMPLING_RATE);
lowRateConfig.validityMask.set(telux::sensor::SensorConfigParams::BATCH_COUNT);
status = lowRateSensorClient->configure(lowRateConfig);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to configure sensor: " << name << std::endl;
exit(1);
}
9. Receive updates on sensor configuration
virtual void onConfigurationUpdate(telux::sensor::SensorConfiguration configuration) override {
PRINT_NOTIFICATION << "(" << name_ << "): Received configuration update from sensor: "
<< sensorClient_->getSensorInfo().name << ": ["
<< configuration.samplingRate << ", " << configuration.batchCount << " ]"
<< std::endl;
}
10. Activate the sensor to receive sensor data
status = lowRateSensorClient->activate();
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to activate sensor: " << name << std::endl;
exit(1);
}
11. Receive sensor data with the registered listener
Avoid any time consuming operation in this callback. This thread should be released back the SDK library to avoid latency.
If any sensor APIs need to be called in this method, they should be done on a different thread. One such method is to spawn a detached thread that invokes the required API.
virtual void onEvent(std::shared_ptr<std::vector<telux::sensor::SensorEvent>> events) override {
PRINT_NOTIFICATION << "(" << name_ << "): Received " << events->size()
<< " events from sensor: " << sensorClient_->getSensorInfo().name
<< std::endl;
for (telux::sensor::SensorEvent s : *(events.get())) {
printSensorEvent(s);
}
++totalBatches_;
if (totalBatches_ > TOTAL_BATCHES_REQUIRED) {
totalBatches_ = 0;
std::thread t([&] {
sensorClient_->deactivate();
sensorClient_->configure(sensorClient_->getConfiguration());
sensorClient_->activate();
});
t.detach();
}
}
12. Create another sensor client for the same sensor and it's corresponding listener
std::shared_ptr<telux::sensor::ISensorClient> highRateSensorClient;
std::cout << "Getting sensor: " << name << std::endl;
status = sensorManager->getSensor(highRateSensorClient, name);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get sensor: " << name << std::endl;
exit(1);
}
std::shared_ptr<SensorEventListener> highRateSensorEventListener
= std::make_shared<SensorEventListener>("High-rate", highRateSensorClient);
highRateSensorClient->registerListener(highRateSensorEventListener);
13. Configure this sensor client with a different configuration, as necessary
telux::sensor::SensorConfiguration highRateConfig;
highRateConfig.samplingRate = getMaximumSamplingRate(highRateSensorClient->getSensorInfo());
highRateConfig.batchCount = highRateSensorClient->getSensorInfo().maxBatchCountSupported;
std::cout << "Configuring sensor with samplingRate, batchCount [" << highRateConfig.samplingRate
<< ", " << highRateConfig.batchCount << "]" << std::endl;
highRateConfig.validityMask.set(telux::sensor::SensorConfigParams::SAMPLING_RATE);
highRateConfig.validityMask.set(telux::sensor::SensorConfigParams::BATCH_COUNT);
status = highRateSensorClient->configure(highRateConfig);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to configure sensor: " << name << std::endl;
exit(1);
}
14. Activate this sensor as well
status = highRateSensorClient->activate();
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to activate sensor: " << name << std::endl;
exit(1);
}
15. When data acquisition is no longer necessary, deactivate the sensors
status = lowRateSensorClient->deactivate();
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to deactivate sensor: " << name << std::endl;
exit(1);
}
status = highRateSensorClient->deactivate();
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to deactivate sensor: " << name << std::endl;
exit(1);
}
16. Release the instances of ISensorClient if no longer required
lowRateSensorClient = nullptr;
highRateSensorClient = nullptr;
17. Release the instance of ISensorManager to cleanup resources
Using Sensor APIs to initiate a self test and acquires the self test result
Please follow below steps as a guide to initiate a self test and acquires the self test result
1. Get sensor factory
auto &sensorFactory = telux::sensor::SensorFactory::getInstance();
2. Prepare a callback that is invoked when the sensor sub-system initialization is complete
std::promise<telux::common::ServiceStatus> p;
auto initCb = [&p](telux::common::ServiceStatus status) {
std::cout << "Received service status: " << static_cast<int>(status) << std::endl;
p.set_value(status);
};
3. Get the sensor manager. If initialization fails, perform necessary error handling
std::shared_ptr<telux::sensor::ISensorManager> sensorManager
= sensorFactory.getSensorManager(initCb);
if (sensorManager == nullptr) {
std::cout << "sensor manager is nullptr" << std::endl;
exit(1);
}
std::cout << "obtained sensor manager" << std::endl;
4. Wait until initialization is complete
p.get_future().get();
if (sensorManager->getServiceStatus() != telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << "Sensor service not available" << std::endl;
exit(1);
}
5. Get information regarding available sensors in the system
std::cout << "Sensor service is now available" << std::endl;
std::vector<telux::sensor::SensorInfo> sensorInfo;
telux::common::Status status = sensorManager->getAvailableSensorInfo(sensorInfo);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get information on available sensors" << static_cast<int>(status)
<< std::endl;
exit(1);
}
std::cout << "Received sensor information" << std::endl;
for (auto info : sensorInfo) {
printSensorInfo(info);
}
6. Request the ISensorManager for the desired sensor
std::shared_ptr<telux::sensor::ISensorClient> sensor;
std::cout << "Getting sensor: " << name << std::endl;
status = sensorManager->getSensor(sensor, name);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get sensor: " << name << std::endl;
exit(1);
}
7. Invoke the self test with the required self test type and provide the callback
status = sensor->selfTest(selfTestType, [](telux::common::ErrorCode result) {
PRINT_CB << "Received self test response: " << static_cast<int>(result) << std::endl;
});
if (status != telux::common::Status::SUCCESS) {
std::cout << "Self test request failed";
} else {
std::cout << "Self test request successful, waiting for callback" << std::endl;
}
8. Release the instance of ISensorClient if no longer required
9. Release the instance of ISensorManager to cleanup resources